From c4e60ed8283aa7a86e13c09113e7fec6bf41cc42 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Fri, 18 Jan 2019 16:02:43 +0100 Subject: Detect Qt via a module provider Creation of qbs modules for Qt is now done on demand during project resolving. The qmake executable(s) are looked up via PATH or taken from the Qt.qmakeFilePaths provider property. As a result, Qt projects can now be built without a profile. The qtprofilesetup library is gone; its code is now in the module provider. I kept the C++ -> JavaScript conversion as straightforward as possible and mostly resisted the temptation to "optimize". The setup-qt tool still exists and mainly sets Qt.qmakeFilePaths. [ChangeLog] It is no longer required to call setup-qt before building Qt projects. Change-Id: I5b7e4711ec47b996911c499f29d8129d90e4731e Reviewed-by: Joerg Bornemann --- doc/qbs.qdoc | 10 +- doc/reference/modules/qt-modules.qdoc | 16 + qbs.pro | 5 +- share/qbs/module-providers/Qt/provider.qbs | 6 + share/qbs/module-providers/Qt/setup-qt.js | 1504 ++++++++++++++++++++ .../qbs/module-providers/Qt/templates/QtModule.qbs | 86 ++ .../qbs/module-providers/Qt/templates/QtPlugin.qbs | 49 + .../Qt/templates/android_support.qbs | 291 ++++ share/qbs/module-providers/Qt/templates/core.qbs | 510 +++++++ share/qbs/module-providers/Qt/templates/dbus.js | 61 + share/qbs/module-providers/Qt/templates/dbus.qbs | 74 + share/qbs/module-providers/Qt/templates/gui.qbs | 65 + share/qbs/module-providers/Qt/templates/moc.js | 102 ++ share/qbs/module-providers/Qt/templates/module.qbs | 30 + share/qbs/module-providers/Qt/templates/plugin.qbs | 27 + .../Qt/templates/plugin_support.qbs | 75 + share/qbs/module-providers/Qt/templates/qdoc.js | 84 ++ share/qbs/module-providers/Qt/templates/qml.js | 66 + share/qbs/module-providers/Qt/templates/qml.qbs | 132 ++ .../qbs/module-providers/Qt/templates/qmlcache.qbs | 85 ++ share/qbs/module-providers/Qt/templates/quick.js | 84 ++ share/qbs/module-providers/Qt/templates/quick.qbs | 211 +++ share/qbs/module-providers/Qt/templates/scxml.qbs | 80 ++ src/app/qbs-setup-android/android-setup.cpp | 8 +- src/app/qbs-setup-qt/main.cpp | 11 +- src/app/qbs-setup-qt/qbs-setup-qt.pro | 1 - src/app/qbs-setup-qt/qbs-setup-qt.qbs | 1 - src/app/qbs-setup-qt/setupqt.cpp | 311 ++-- src/app/qbs-setup-qt/setupqt.h | 25 +- .../corelib/jsextensions/utilitiesextension.cpp | 262 ++++ src/lib/libs.qbs | 1 - src/lib/qtprofilesetup/qtenvironment.h | 101 -- src/lib/qtprofilesetup/qtmoduleinfo.cpp | 839 ----------- src/lib/qtprofilesetup/qtmoduleinfo.h | 115 -- src/lib/qtprofilesetup/qtmsvctools.cpp | 79 - src/lib/qtprofilesetup/qtmsvctools.h | 49 - src/lib/qtprofilesetup/qtprofilesetup.cpp | 930 ------------ src/lib/qtprofilesetup/qtprofilesetup.h | 59 - src/lib/qtprofilesetup/qtprofilesetup.pro | 31 - src/lib/qtprofilesetup/qtprofilesetup.qbs | 31 - src/lib/qtprofilesetup/templates.qrc | 22 - src/lib/qtprofilesetup/templates/QtModule.qbs | 86 -- src/lib/qtprofilesetup/templates/QtPlugin.qbs | 49 - .../qtprofilesetup/templates/android_support.qbs | 291 ---- src/lib/qtprofilesetup/templates/core.qbs | 510 ------- src/lib/qtprofilesetup/templates/dbus.js | 61 - src/lib/qtprofilesetup/templates/dbus.qbs | 74 - src/lib/qtprofilesetup/templates/gui.qbs | 65 - src/lib/qtprofilesetup/templates/moc.js | 102 -- src/lib/qtprofilesetup/templates/module.qbs | 30 - src/lib/qtprofilesetup/templates/plugin.qbs | 27 - .../qtprofilesetup/templates/plugin_support.qbs | 75 - src/lib/qtprofilesetup/templates/qdoc.js | 84 -- src/lib/qtprofilesetup/templates/qml.js | 66 - src/lib/qtprofilesetup/templates/qml.qbs | 132 -- src/lib/qtprofilesetup/templates/qmlcache.qbs | 85 -- src/lib/qtprofilesetup/templates/quick.js | 84 -- src/lib/qtprofilesetup/templates/quick.qbs | 211 --- src/lib/qtprofilesetup/templates/scxml.qbs | 80 -- .../use_installed_qtprofilesetup.pri | 20 - src/lib/qtprofilesetup/use_qtprofilesetup.pri | 46 - src/packages/archive/archive.qbs | 1 - tests/auto/blackbox/tst_blackboxqt.cpp | 15 +- 63 files changed, 4018 insertions(+), 4705 deletions(-) create mode 100644 share/qbs/module-providers/Qt/provider.qbs create mode 100644 share/qbs/module-providers/Qt/setup-qt.js create mode 100644 share/qbs/module-providers/Qt/templates/QtModule.qbs create mode 100644 share/qbs/module-providers/Qt/templates/QtPlugin.qbs create mode 100644 share/qbs/module-providers/Qt/templates/android_support.qbs create mode 100644 share/qbs/module-providers/Qt/templates/core.qbs create mode 100644 share/qbs/module-providers/Qt/templates/dbus.js create mode 100644 share/qbs/module-providers/Qt/templates/dbus.qbs create mode 100644 share/qbs/module-providers/Qt/templates/gui.qbs create mode 100644 share/qbs/module-providers/Qt/templates/moc.js create mode 100644 share/qbs/module-providers/Qt/templates/module.qbs create mode 100644 share/qbs/module-providers/Qt/templates/plugin.qbs create mode 100644 share/qbs/module-providers/Qt/templates/plugin_support.qbs create mode 100644 share/qbs/module-providers/Qt/templates/qdoc.js create mode 100644 share/qbs/module-providers/Qt/templates/qml.js create mode 100644 share/qbs/module-providers/Qt/templates/qml.qbs create mode 100644 share/qbs/module-providers/Qt/templates/qmlcache.qbs create mode 100644 share/qbs/module-providers/Qt/templates/quick.js create mode 100644 share/qbs/module-providers/Qt/templates/quick.qbs create mode 100644 share/qbs/module-providers/Qt/templates/scxml.qbs delete mode 100644 src/lib/qtprofilesetup/qtenvironment.h delete mode 100644 src/lib/qtprofilesetup/qtmoduleinfo.cpp delete mode 100644 src/lib/qtprofilesetup/qtmoduleinfo.h delete mode 100644 src/lib/qtprofilesetup/qtmsvctools.cpp delete mode 100644 src/lib/qtprofilesetup/qtmsvctools.h delete mode 100644 src/lib/qtprofilesetup/qtprofilesetup.cpp delete mode 100644 src/lib/qtprofilesetup/qtprofilesetup.h delete mode 100644 src/lib/qtprofilesetup/qtprofilesetup.pro delete mode 100644 src/lib/qtprofilesetup/qtprofilesetup.qbs delete mode 100644 src/lib/qtprofilesetup/templates.qrc delete mode 100644 src/lib/qtprofilesetup/templates/QtModule.qbs delete mode 100644 src/lib/qtprofilesetup/templates/QtPlugin.qbs delete mode 100644 src/lib/qtprofilesetup/templates/android_support.qbs delete mode 100644 src/lib/qtprofilesetup/templates/core.qbs delete mode 100644 src/lib/qtprofilesetup/templates/dbus.js delete mode 100644 src/lib/qtprofilesetup/templates/dbus.qbs delete mode 100644 src/lib/qtprofilesetup/templates/gui.qbs delete mode 100644 src/lib/qtprofilesetup/templates/moc.js delete mode 100644 src/lib/qtprofilesetup/templates/module.qbs delete mode 100644 src/lib/qtprofilesetup/templates/plugin.qbs delete mode 100644 src/lib/qtprofilesetup/templates/plugin_support.qbs delete mode 100644 src/lib/qtprofilesetup/templates/qdoc.js delete mode 100644 src/lib/qtprofilesetup/templates/qml.js delete mode 100644 src/lib/qtprofilesetup/templates/qml.qbs delete mode 100644 src/lib/qtprofilesetup/templates/qmlcache.qbs delete mode 100644 src/lib/qtprofilesetup/templates/quick.js delete mode 100644 src/lib/qtprofilesetup/templates/quick.qbs delete mode 100644 src/lib/qtprofilesetup/templates/scxml.qbs delete mode 100644 src/lib/qtprofilesetup/use_installed_qtprofilesetup.pri delete mode 100644 src/lib/qtprofilesetup/use_qtprofilesetup.pri diff --git a/doc/qbs.qdoc b/doc/qbs.qdoc index f559b481d..a87e88bdc 100644 --- a/doc/qbs.qdoc +++ b/doc/qbs.qdoc @@ -675,7 +675,7 @@ 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 the installation paths of the Qt modules. + as \l{Qt-specific Module Provider Properties}{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 @@ -707,7 +707,7 @@ \endcode You have successfully built your first \QBS project. If you want to build - projects that use Qt, additional steps are necessary. Please refer to + projects that use Qt, additional steps might be necessary. Please refer to \l{Managing Qt Versions} for more information. \section1 Global Preferences @@ -754,10 +754,10 @@ \section1 Introduction - To let \QBS know where the Qt build or Qt version is that you want to use, - you must register it. + 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: - Register a Qt version like this: \code qbs setup-qt /usr/bin/qmake myqt \endcode diff --git a/doc/reference/modules/qt-modules.qdoc b/doc/reference/modules/qt-modules.qdoc index 638160104..df5219ccd 100644 --- a/doc/reference/modules/qt-modules.qdoc +++ b/doc/reference/modules/qt-modules.qdoc @@ -55,6 +55,22 @@ The Qt modules that have properties and relevant file tags are described in separate topics. + \section1 Qt-specific Module Provider Properties + + 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 \c Qt.qmakeFilePaths + \l{Parameterizing Module Providers}{module provider 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. + \section1 List of Submodules \table diff --git a/qbs.pro b/qbs.pro index 8b4fe3f9d..4be68099b 100644 --- a/qbs.pro +++ b/qbs.pro @@ -31,10 +31,8 @@ defineTest(minQtVersion) { TEMPLATE = subdirs corelib.file = src/lib/corelib/corelib.pro -setupqtprofilelib.subdir = src/lib/qtprofilesetup -setupqtprofilelib.depends = corelib src_app.subdir = src/app -src_app.depends = setupqtprofilelib +src_app.depends = corelib src_libexec.subdir = src/libexec src_plugins.subdir = src/plugins CONFIG(shared, static|shared): src_plugins.depends = corelib @@ -48,7 +46,6 @@ qbs_use_bundled_qtscript { } SUBDIRS += \ corelib\ - setupqtprofilelib\ src_app\ src_libexec\ src_plugins\ diff --git a/share/qbs/module-providers/Qt/provider.qbs b/share/qbs/module-providers/Qt/provider.qbs new file mode 100644 index 000000000..33083c51d --- /dev/null +++ b/share/qbs/module-providers/Qt/provider.qbs @@ -0,0 +1,6 @@ +import "setup-qt.js" as SetupQt + +ModuleProvider { + property stringList qmakeFilePaths + relativeSearchPaths: SetupQt.doSetup(qmakeFilePaths, outputBaseDir, path, qbs) +} diff --git a/share/qbs/module-providers/Qt/setup-qt.js b/share/qbs/module-providers/Qt/setup-qt.js new file mode 100644 index 000000000..0f0755409 --- /dev/null +++ b/share/qbs/module-providers/Qt/setup-qt.js @@ -0,0 +1,1504 @@ +/**************************************************************************** +** +** 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 Process = require("qbs.Process"); +var TextFile = require("qbs.TextFile"); +var Utilities = require("qbs.Utilities"); + +function splitNonEmpty(s, c) { return s.split(c).filter(function(e) { return e; }); } +function toNative(p) { return FileInfo.toNativeSeparators(p); } +function exeSuffix(qbs) { return qbs.hostOS.contains("windows") ? ".exe" : ""; } + +function getQmakeFilePaths(qmakeFilePaths, qbs) { + if (qmakeFilePaths && qmakeFilePaths.length > 0) + return qmakeFilePaths; + console.info("Detecting Qt installations..."); + var pathValue = Environment.getEnv("PATH"); + if (!pathValue) + return []; + var dirs = splitNonEmpty(pathValue, qbs.pathListSeparator); + var suffix = exeSuffix(qbs); + var filePaths = []; + for (var i = 0; i < dirs.length; ++i) { + var candidate = FileInfo.canonicalPath(FileInfo.joinPaths(dirs[i], "qmake" + suffix)); + if (candidate && File.exists(candidate) && !filePaths.contains(candidate)) { + console.info("Found Qt at '" + toNative(candidate) + "'."); + filePaths.push(candidate); + } + } + return filePaths; +} + +function queryQmake(qmakeFilePath) { + var qmakeProcess = new Process; + qmakeProcess.exec(qmakeFilePath, ["-query"]); + 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) { + return splitNonEmpty(configVariable(configContent, key), ' '); +} + +function msvcPrefix() { return "win32-msvc"; } + +function isMsvcQt(qtProps) { return qtProps.mkspecName.startsWith(msvcPrefix()); } + +function msvcCompilerVersionForYear(year) { + var mapping = { + "2005": "14", "2008": "15", "2010": "16", "2012": "17", "2013": "18", "2015": "19", + "2017": "19.1" + }; + 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 isForMinGw(qtProps) { + return qtProps.mkspecName.startsWith("win32-g++") || qtProps.mkspecName.startsWith("mingw"); +} + +function targetsDesktopWindows(qtProps) { + return qtProps.mkspecName.startsWith("win32-") || isForMinGw(qtProps); +} + +function guessMinimumWindowsVersion(qtProps) { + if (qtProps.mkspecName.startsWith("winrt-")) + return "10.0"; + if (!targetsDesktopWindows(qtProps)) + return ""; + 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 = isForMinGw(qtProps); + + // Some Linux distributions rename the qtmain library. + var qtMainCandidates = ["qtmain"]; + if (isMinGW && qtProps.qtMajorVersion === 5) + qtMainCandidates.push("qt5main"); + + 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) + 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 '" + toNative(qtProps.libraryPath) + + "'. You will not be able to link Qt applications."); + } + return result; +} + +function getQtProperties(qmakeFilePath, qbs) { + var queryResult = queryQmake(qmakeFilePath); + var qtProps = {}; + qtProps.installPrefixPath = pathQueryValue(queryResult, "QT_INSTALL_PREFIX"); + qtProps.documentationPath = pathQueryValue(queryResult, "QT_INSTALL_DOCS"); + qtProps.includePath = pathQueryValue(queryResult, "QT_INSTALL_HEADERS"); + qtProps.libraryPath = pathQueryValue(queryResult, "QT_INSTALL_LIBS"); + qtProps.binaryPath = pathQueryValue(queryResult, "QT_HOST_BINS") + || pathQueryValue(queryResult, "QT_INSTALL_BINS"); + qtProps.documentationPath = pathQueryValue(queryResult, "QT_INSTALL_DOCS"); + 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 (!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"); + + // 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 (qbs.hostOS.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 '" + toNative(qtProps.mkspecPath) + "' does not exist"; + + // determine MSVC version + if (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); + + // 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) { + try { + var qmakeConf = new TextFile(FileInfo.joinPaths(qtProps.mkspecPath, "qmake.conf"), + TextFile.ReadOnly); + while (!qmakeConf.atEof()) { + var line = qmakeConf.readLine().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; + } + } + } + catch (e) {} + finally { + if (qmakeConf) + qmakeConf.close(); + } + 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 '" + + toNative(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 !== "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.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 (isFramework(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 isFramework(modInfo, qtProps) { + if (!qtProps.frameworkBuild || modInfo.isStaticLibrary) + return false; + var modulesNeverBuiltAsFrameworks = [ + "bootstrap", "openglextensions", "platformsupport", "qmldevtools", "uitools", "harfbuzzng" + ]; + return !modulesNeverBuiltAsFrameworks.contains(modInfo.qbsName); +} + +function libBaseName(modInfo, libName, debugBuild, qtProps) { + var name = libName; + if (qtProps.mkspecName.startsWith("win")) { + if (debugBuild) + 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 (!isFramework(modInfo, qtProps) + && qtProps.buildVariant.contains("debug") + && (!qtProps.buildVariant.contains("release") || debugBuild)) { + name += "_debug"; + } + } + return name; +} + +function moduleNameWithoutPrefix(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 libraryBaseName(modInfo, qtProps, debugBuild) { + if (modInfo.isPlugin) + return libBaseName(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 = !modInfo.modulePrefix && !libNameBroken ? "Qt" : modInfo.modulePrefix; + if (qtProps.qtMajorVersion >= 5 && !isFramework(modInfo, qtProps) && !libNameBroken) + libName += qtProps.qtMajorVersion; + libName += moduleNameWithoutPrefix(modInfo); + libName += qtProps.qtLibInfix; + return libBaseName(modInfo, libName, debugBuild, qtProps); +} + +function libNameForLinker(modInfo, qtProps, debugBuild) { + if (!modInfo.hasLibrary) + return undefined; + var libName = libraryBaseName(modInfo, qtProps, debugBuild); + if (qtProps.mkspecName.contains("msvc")) + libName += ".lib"; + return libName; +} + +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[libNameForLinker(m, qtProps, true)] = m.libFilePathDebug; + linkerNamesToFilePathsRelease[libNameForLinker(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) { + 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(libNameForLinker(platformSupportModule, qtProps, debugBuild)); + } + if (modInfo.name === "qios") { + flags.push("-force_load", FileInfo.joinPaths( + qtProps.pluginPath, "platforms", + libBaseName(modInfo, "libqios", debugBuild, qtProps) + ".a")); + } + } + var prlFilePath = modInfo.isPlugin + ? FileInfo.joinPaths(qtProps.pluginPath, modInfo.pluginData.type) + : qtProps.libraryPath; + if (isFramework(modInfo, qtProps)) { + prlFilePath = FileInfo.joinPaths(prlFilePath, + libraryBaseName(modInfo, qtProps, false) + ".framework"); + } + var libDir = prlFilePath; + var baseName = libraryBaseName(modInfo, qtProps, debugBuild); + if (!qtProps.mkspecName.startsWith("win") && !isFramework(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... + 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; + + // Assuming lib names and directories without spaces here. + var parts = splitNonEmpty(line.slice(equalsOffset + 1).trim(), ' '); + for (i = 0; i < parts.length; ++i) { + var part = parts[i]; + part = part.replace("$$[QT_INSTALL_LIBS]", qtProps.libraryPath); + 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") { + 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) { + libFilePath = guessLibraryFilePath(prlFilePath, libDir, qtProps); + if (nonExistingPrlFiles.contains(prlFilePath)) + return; + nonExistingPrlFiles.push(prlFilePath); + if (!libFilePath && modInfo.mustExist) { + console.warn("Could not open prl file '" + toNative(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) { + doSetupLibraries(qtModuleInfo, qtProps, true, nonExistingPrlFiles); + doSetupLibraries(qtModuleInfo, qtProps, false, nonExistingPrlFiles); +} + +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 getPriFileContentsRecursively(priFilePath) { + var priFile = new TextFile(priFilePath, TextFile.ReadOnly); + var lines = splitNonEmpty(priFile.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 '" + toNative(priFilePath) + "'"); + continue; + } + var includedFilePath = line.slice(offset, closingParenPos - offset); + var includedContents = getPriFileContentsRecursively(includedFilePath); + var j = i; + for (var k = 0; k < includedContents.length; ++k) + lines.splice(++j, 0, includedContents[k]); + lines.splice(i--, 1); + } + priFile.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 '" + toNative(filePath) + "'"); + break; + } + } else { + endIndex = rhs.indexOf(' ', startIndex + 1); + if (endIndex === -1) + endIndex = rhs.length; + } + paths.push(rhs.slice(startIndex, endIndex)); + 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]) + revDeps[depmod] = []; + revDeps[depmod].push(module); + } + } + } + + function roots(modules) { + var result = []; + for (i = 0; i < modules.length; ++i) { + var module = modules[i] + if (module.dependencies.lenegth === 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(); + + for (i = 0; i < (revDeps[module] || []).length; ++i) + traverse(revDeps[module][i], libs); + + m_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) { + 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 moduleFileNamePrefix = "qt_lib_"; + var pluginFileNamePrefix = "qt_plugin_"; + var moduleFileNameSuffix = ".pri"; + var fileHasPluginPrefix = priFileName.startsWith(pluginFileNamePrefix); + if (!fileHasPluginPrefix && (!priFileName.startsWith(moduleFileNamePrefix)) + || !priFileName.endsWith(moduleFileNameSuffix)) { + continue; + } + var moduleInfo = makeQtModuleInfo(); + moduleInfo.isPlugin = fileHasPluginPrefix; + var fileNamePrefix = moduleInfo.isPlugin ? pluginFileNamePrefix : 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 = getPriFileContentsRecursively(priFilePath); + 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 (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_LIB_BASE", 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.splice(k, 1); + moduleInfo.pluginData.autoLoad = false; + break; + } + } + } else if (key.endsWith(".CLASS_NAME")) { + moduleInfo.pluginData.className = value; + } + } + if (hasV2 && !hasModuleEntry) + moduleInfo.hasLibrary = false; + + // Fix include paths for Apple frameworks. + // The qt_lib_XXX.pri files contain wrong values for versions < 5.6. + if (!hasV2 && isFramework(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); + + modules.push(moduleInfo); + if (moduleInfo.qbsName === "testlib") + addTestModule(modules); + if (moduleInfo.qbsName === "designercomponents-private") + addDesignerComponentsModule(modules); + } + + replaceQtLibNamesWithFilePath(modules, qtProps); + removeDuplicatedDependencyLibs(modules); + return modules; +} + +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 (targetsDesktopWindows(qtProps) || mkspec.startsWith("winrt-")) + return "windows"; +} + +function pathToJSLiteral(path) { return JSON.stringify(FileInfo.fromNativeSeparators(path)); } + +function defaultQpaPlugin(module, qtProps) { + if (qtProps.qtMajorVersion < 5) + return undefined; + if (qtProps.qtMajorVersion === 5 && qtProps.qtMinorVersion < 8) { + var qConfigPri = new TextFile(FileInfo.joinPaths(qtProps.mkspecBasePath, "qconfig.pri")); + var magicString = "QT_DEFAULT_QPA_PLUGIN ="; + while (!qConfigPri.atEof()) { + var line = qConfigPri.readLine().trim(); + if (line.startsWith(magicString)) + return line.slice(magicString.length).trim(); + } + qConfigPri.close(); + } else { + 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()) { + 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.isAbsolute(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 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 toJSLiteral(v) { + if (v === undefined) + return "undefined"; + return JSON.stringify(v); +} + +function minVersionJsString(minVersion) { + return !minVersion ? "original" : toJSLiteral(minVersion); +} + +function replaceSpecialValues(content, module, qtProps) { + var dict = { + archs: toJSLiteral(extractQbsArchs(module, qtProps)), + targetPlatform: toJSLiteral(qbsTargetPlatformFromQtMkspec(qtProps)), + config: toJSLiteral(qtProps.configItems), + qtConfig: toJSLiteral(qtProps.qtConfigItems), + binPath: toJSLiteral(qtProps.binaryPath), + libPath: toJSLiteral(qtProps.libraryPath), + pluginPath: toJSLiteral(qtProps.pluginPath), + incPath: toJSLiteral(qtProps.includePath), + docPath: toJSLiteral(qtProps.documentationPath), + mkspecName: toJSLiteral(qtProps.mkspecName), + mkspecPath: toJSLiteral(qtProps.mkspecPath), + version: toJSLiteral(qtProps.qtVersion), + libInfix: toJSLiteral(qtProps.qtLibInfix), + availableBuildVariants: toJSLiteral(qtProps.buildVariant), + staticBuild: toJSLiteral(qtProps.staticBuild), + frameworkBuild: toJSLiteral(qtProps.frameworkBuild), + name: toJSLiteral(moduleNameWithoutPrefix(module)), + has_library: toJSLiteral(module.hasLibrary), + dependencies: toJSLiteral(module.dependencies), + includes: toJSLiteral(module.includePaths), + staticLibsDebug: toJSLiteral(module.staticLibrariesDebug), + staticLibsRelease: toJSLiteral(module.staticLibrariesRelease), + dynamicLibsDebug: toJSLiteral(module.dynamicLibrariesDebug), + dynamicLibsRelease: toJSLiteral(module.dynamicLibrariesRelease), + linkerFlagsDebug: toJSLiteral(module.linkerFlagsDebug), + linkerFlagsRelease: toJSLiteral(module.linkerFlagsRelease), + libraryPaths: toJSLiteral(module.libraryPaths), + frameworkPathsDebug: toJSLiteral(module.frameworkPathsDebug), + frameworkPathsRelease: toJSLiteral(module.frameworkPathsRelease), + frameworksDebug: toJSLiteral(module.frameworksDebug), + frameworksRelease: toJSLiteral(module.frameworksRelease), + libFilePathDebug: toJSLiteral(module.libFilePathDebug), + libFilePathRelease: toJSLiteral(module.libFilePathRelease), + libNameForLinkerDebug: toJSLiteral(libNameForLinker(module, qtProps, true)), + pluginTypes: toJSLiteral(module.supportedPluginTypes), + moduleConfig: toJSLiteral(module.config), + libNameForLinkerRelease: toJSLiteral(libNameForLinker(module, qtProps, false)), + entryPointLibsDebug: toJSLiteral(qtProps.entryPointLibsDebug), + entryPointLibsRelease: toJSLiteral(qtProps.entryPointLibsRelease), + minWinVersion: minVersionJsString(qtProps.windowsVersion), + minMacVersion: minVersionJsString(qtProps.macosVersion), + minIosVersion: minVersionJsString(qtProps.iosVersion), + minTvosVersion: minVersionJsString(qtProps.tvosVersion), + minWatchosVersion: minVersionJsString(qtProps.watchosVersion), + minAndroidVersion: minVersionJsString(qtProps.androidVersion), + }; + + var additionalContent = ""; + var compilerDefines = 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 = 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 = toJSLiteral(module.pluginData.className); + dict["extends"] = toJSLiteral(module.pluginData["extends"]); + } + if (module.hasLibrary && !isFramework(module, qtProps)) { + if (additionalContent) + additionalContent += "\n"; + indent = " "; + additionalContent += "Group {\n"; + if (module.isPlugin) { + additionalContent += indent + indent + + "condition: Qt[\"" + module.qbsName + "\"].enableLinking\n"; + } + additionalContent += indent + indent + "files: [Qt[\"" + module.qbsName + "\"]" + + ".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 replacement = dict[content.slice(pos[0] + 1, pos[1])] || ""; + content = content.slice(0, pos[0]) + replacement + content.slice(pos[1] + 1); + pos[0] += replacement.length; + } + return content; +} + +function copyTemplateFile(fileName, targetDirectory, qtProps, location, allFiles, module, pluginMap, + nonEssentialPlugins) +{ + if (!File.makePath(targetDirectory)) { + throw "Cannot create directory '" + toNative(targetDirectory) + "'."; + } + var sourceFile = new TextFile(FileInfo.joinPaths(location, "templates", fileName), + TextFile.ReadOnly); + var newContent = sourceFile.readAll(); + if (module) { + newContent = replaceSpecialValues(newContent, module, qtProps); + } else { + newContent = newContent.replace("@allPluginsByType@", + '(' + toJSLiteral(pluginMap) + ')'); + newContent = newContent.replace("@nonEssentialPlugins@", + toJSLiteral(nonEssentialPlugins)); + } + 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(qmakeFilePath, outputBaseDir, uniquify, location, qbs) { + if (!File.exists(qmakeFilePath)) + throw "The specified qmake file path '" + toNative(qmakeFilePath) + "' does not exist."; + var qtProps = getQtProperties(qmakeFilePath, qbs); + var modules = qtProps.qtMajorVersion < 5 ? allQt4Modules(qtProps) : allQt5Modules(qtProps); + var pluginsByType = []; + var nonEssentialPlugins = []; + for (var i = 0; i < modules.length; ++i) { + var m = modules[i]; + if (m.isPlugin) { + if (!pluginsByType[m.pluginData.type]) + pluginsByType[m.pluginData.type] = []; + pluginsByType[m.pluginData.type].push(m.name); + if (!m.pluginData.autoLoad) + nonEssentialPlugins.push(m.name); + } + } + + var relativeSearchPath = uniquify ? Utilities.getHash(qmakeFilePath) : ""; + var qbsQtModuleBaseDir = FileInfo.joinPaths(outputBaseDir, relativeSearchPath, "modules", "Qt"); + if (File.exists(qbsQtModuleBaseDir)) + File.remove(qbsQtModuleBaseDir); + + var allFiles = []; + copyTemplateFile("QtModule.qbs", qbsQtModuleBaseDir, qtProps, location, allFiles); + copyTemplateFile("QtPlugin.qbs", qbsQtModuleBaseDir, qtProps, location, allFiles); + copyTemplateFile("plugin_support.qbs", FileInfo.joinPaths(qbsQtModuleBaseDir, "plugin_support"), + qtProps, location, allFiles, undefined, pluginsByType, nonEssentialPlugins); + + for (i = 0; i < modules.length; ++i) { + var module = modules[i]; + var qbsQtModuleDir = FileInfo.joinPaths(qbsQtModuleBaseDir, module.qbsName); + var moduleTemplateFileName; + if (module.qbsName === "core") { + moduleTemplateFileName = "core.qbs"; + copyTemplateFile("moc.js", qbsQtModuleDir, qtProps, location, allFiles); + copyTemplateFile("qdoc.js", qbsQtModuleDir, qtProps, 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, location, allFiles); + } else if (module.qbsName === "qml") { + moduleTemplateFileName = "qml.qbs"; + copyTemplateFile("qml.js", qbsQtModuleDir, qtProps, location, allFiles); + var qmlcacheStr = "qmlcache"; + if (File.exists(FileInfo.joinPaths(qtProps.binaryPath, + "qmlcachegen" + exeSuffix(qbs)))) { + copyTemplateFile(qmlcacheStr + ".qbs", + FileInfo.joinPaths(qbsQtModuleBaseDir, qmlcacheStr), qtProps, + location, allFiles); + } + } else if (module.qbsName === "quick") { + moduleTemplateFileName = "quick.qbs"; + copyTemplateFile("quick.js", qbsQtModuleDir, qtProps, location, allFiles); + } else if (module.isPlugin) { + moduleTemplateFileName = "plugin.qbs"; + } else { + moduleTemplateFileName = "module.qbs"; + } + copyTemplateFile(moduleTemplateFileName, qbsQtModuleDir, qtProps, location, allFiles, + module); + } + + // 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, location, allFiles); + return relativeSearchPath; +} + +function doSetup(qmakeFilePaths, outputBaseDir, location, qbs) { + qmakeFilePaths = getQmakeFilePaths(qmakeFilePaths, qbs); + if (!qmakeFilePaths || qmakeFilePaths.length === 0) + return []; + var uniquifySearchPath = qmakeFilePaths.length > 1; + var searchPaths = []; + for (var i = 0; i < qmakeFilePaths.length; ++i) { + try { + console.info("Setting up Qt at '" + toNative(qmakeFilePaths[i]) + "'..."); + var searchPath = setupOneQt(qmakeFilePaths[i], outputBaseDir, uniquifySearchPath, + location, qbs); + if (searchPath !== undefined) { + searchPaths.push(searchPath); + console.info("Qt was set up successfully."); + } + } catch (e) { + console.warn("Error setting up Qt for '" + toNative(qmakeFilePaths[i]) + "': " + e); + } + } + return searchPaths; +} diff --git a/share/qbs/module-providers/Qt/templates/QtModule.qbs b/share/qbs/module-providers/Qt/templates/QtModule.qbs new file mode 100644 index 000000000..aa7c1d15a --- /dev/null +++ b/share/qbs/module-providers/Qt/templates/QtModule.qbs @@ -0,0 +1,86 @@ +import 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. + // 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 + version: Qt.core.version + 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.frameworkPaths: mFrameworkPaths + } +} diff --git a/share/qbs/module-providers/Qt/templates/QtPlugin.qbs b/share/qbs/module-providers/Qt/templates/QtPlugin.qbs new file mode 100644 index 000000000..23a6795f3 --- /dev/null +++ b/share/qbs/module-providers/Qt/templates/QtPlugin.qbs @@ -0,0 +1,49 @@ +import 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.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" + } + + 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; + } + } +} diff --git a/share/qbs/module-providers/Qt/templates/android_support.qbs b/share/qbs/module-providers/Qt/templates/android_support.qbs new file mode 100644 index 000000000..79276a494 --- /dev/null +++ b/share/qbs/module-providers/Qt/templates/android_support.qbs @@ -0,0 +1,291 @@ +import qbs.File +import qbs.FileInfo +import qbs.ModUtils +import qbs.TextFile +import qbs.Utilities + +Module { + property bool useMinistro: false + property string qmlRootDir: product.sourceDirectory + property stringList extraPrefixDirs + property stringList deploymentDependencies // qmake: ANDROID_DEPLOYMENT_DEPENDENCIES + property stringList extraPlugins // qmake: ANDROID_EXTRA_PLUGINS + property bool verboseAndroidDeployQt: false + + property string _androidDeployQtFilePath: FileInfo.joinPaths(_qtInstallDir, "bin", + "androiddeployqt") + property string _qtInstallDir + property bool _enableSdkSupport: product.type && product.type.contains("android.apk") + && !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") + + Depends { name: "Android.sdk"; condition: _enableSdkSupport } + Depends { name: "Android.ndk"; condition: _enableNdkSupport } + Depends { name: "java"; condition: _enableSdkSupport } + + Properties { + condition: _enableNdkSupport && qbs.toolchain.contains("clang") + Android.ndk.appStl: "c++_shared" + } + Properties { + condition: _enableNdkSupport && !qbs.toolchain.contains("clang") + Android.ndk.appStl: "gnustl_shared" + } + Properties { + condition: _enableSdkSupport + Android.sdk.customManifestProcessing: true + java._tagJniHeaders: false // prevent rule cycle + } + + Rule { + condition: _enableSdkSupport + multiplex: true + property stringList inputTags: "android.nativelibrary" + inputsFromDependencies: inputTags + inputs: product.aggregate ? [] : inputTags + Artifact { + filePath: "androiddeployqt.json" + fileTags: "qt_androiddeployqt_input" + } + prepare: { + var cmd = new JavaScriptCommand(); + cmd.description = "creating " + output.fileName; + cmd.sourceCode = function() { + var theBinary; + var nativeLibs = inputs["android.nativelibrary"]; + if (nativeLibs.length === 1) { + theBinary = nativeLibs[0]; + } else { + for (i = 0; i < nativeLibs.length; ++i) { + var candidate = nativeLibs[i]; + if (!candidate.fileName.contains(candidate.product.targetName)) + continue; + if (!theBinary) { + theBinary = candidate; + continue; + } + if (theBinary.product.name === product.name + && candidate.product.name !== product.name) { + continue; // We already have a better match. + } + if (candidate.product.name === product.name + && theBinary.product.name !== product.name) { + theBinary = candidate; // The new candidate is a better match. + 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.",'); + 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 + '",'); + var toolPrefix = theBinary.cpp.toolchainTriple; + var toolchainPrefix = toolPrefix.startsWith("i686-") ? "x86" : toolPrefix; + f.writeLine('"toolchain-prefix": "' + toolchainPrefix + '",'); + f.writeLine('"tool-prefix": "' + toolPrefix + '",'); + f.writeLine('"toolchain-version": "' + theBinary.Android.ndk.toolchainVersion + + '",'); + f.writeLine('"ndk-host": "' + theBinary.Android.ndk.hostArch + '",'); + f.writeLine('"target-architecture": "' + theBinary.Android.ndk.abi + '",'); + 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 prefixDirs = product.Qt.android_support.extraPrefixDirs; + if (prefixDirs && prefixDirs.length > 0) + f.writeLine('"extraPrefixDirs": ' + JSON.stringify(prefixDirs) + ','); + if (Array.isArray(product.qmlImportPaths) && product.qmlImportPaths.length > 0) + f.writeLine('"qml-import-paths": "' + product.qmlImportPaths.join(',') + '",'); + f.writeLine('"application-binary": "' + theBinary.filePath + '"'); + f.writeLine("}"); + f.close(); + }; + return cmd; + } + } + + // We use the manifest template from the Qt installation if and only if the project + // does not provide a manifest file. + Rule { + condition: _enableSdkSupport + multiplex: true + requiresInputs: false + inputs: "android.manifest" + excludedInputs: "qt.android_manifest" + outputFileTags: ["android.manifest", "qt.android_manifest"] + outputArtifacts: { + if (inputs["android.manifest"]) + return []; + return [{ + filePath: "qt_manifest/AndroidManifest.xml", + fileTags: ["android.manifest", "qt.android_manifest"] + }]; + } + prepare: { + 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; + } + } + + Rule { + condition: _enableSdkSupport + multiplex: true + inputs: ["qt_androiddeployqt_input", "android.manifest_processed"] + outputFileTags: [ + "android.manifest_final", "android.resources", "android.assets", "bundled_jar", + "android.deployqt_list", + ] + outputArtifacts: { + var artifacts = [ + { + 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" + }, + + ]; + if (!product.Qt.android_support.useMinistro) { + artifacts.push({ + filePath: FileInfo.joinPaths(product.java.classFilesDir, "QtAndroid.jar"), + fileTags: ["bundled_jar"] + }); + } + return artifacts; + } + prepare: { + 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"); + try { + File.remove(FileInfo.path(outputs["android.assets"][0].filePath)); + } catch (e) { + } + }; + var androidDeployQtArgs = [ + "--output", product.Qt.android_support._deployQtOutDir, + "--input", inputs["qt_androiddeployqt_input"][0].filePath, "--aux-mode", + "--deployment", product.Qt.android_support.useMinistro ? "ministro" : "bundled", + "--android-platform", product.Android.sdk.platform, + ]; + if (product.Qt.android_support.verboseAndroidDeployQt) + args.push("--verbose"); + var androidDeployQtCmd = new Command( + product.Qt.android_support._androidDeployQtFilePath, androidDeployQtArgs); + androidDeployQtCmd.description = "running androiddeployqt"; + + // 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 outout"; + moveCmd.sourceCode = function() { + File.move(product.Qt.android_support._deployQtOutDir + "/AndroidManifest.xml", + outputs["android.manifest_final"][0].filePath); + var libsDir = product.Qt.android_support._deployQtOutDir + "/libs"; + var libDir = product.Android.sdk.apkContentsDir + "/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]); + } + }; + return [copyCmd, androidDeployQtCmd, moveCmd]; + } + } + + Group { + condition: Qt.android_support._enableSdkSupport + name: "helper sources from qt" + prefix: Qt.android_support._templatesBaseDir + "/java/" + Android.sdk.aidlSearchPaths: prefix + "src" + files: [ + "**/*.java", + "**/*.aidl", + ] + } + + validate: { + if (Utilities.versionCompare(version, "5.12") < 0) + throw ModUtils.ModuleError("Cannot use Qt " + version + " with Android. " + + "Version 5.12 or later is required."); + } +} diff --git a/share/qbs/module-providers/Qt/templates/core.qbs b/share/qbs/module-providers/Qt/templates/core.qbs new file mode 100644 index 000000000..b2f05d8e9 --- /dev/null +++ b/share/qbs/module-providers/Qt/templates/core.qbs @@ -0,0 +1,510 @@ +import qbs.FileInfo +import qbs.ModUtils +import qbs.TextFile +import qbs.Utilities +import qbs.Xml +import "moc.js" as Moc +import "qdoc.js" as Qdoc + +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.android_support"; condition: qbs.targetOS.contains("android") } + Properties { + condition: qbs.targetOS.contains("android") + Qt.android_support._qtInstallDir: FileInfo.path(binPath) + Qt.android_support.version: version + } + + version: @version@ + property stringList architectures: @archs@ + property string targetPlatform: @targetPlatform@ + property string libInfix: @libInfix@ + property stringList config: @config@ + property stringList qtConfig: @qtConfig@ + property path binPath: @binPath@ + property path incPath: @incPath@ + property path libPath: @libPath@ + 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 qdocName: versionMajor >= 5 ? "qdoc" : "qdoc3" + property stringList qdocEnvironment + property path docPath: @docPath@ + 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 stringList pluginMetaData: [] + property bool enableKeywords: true + + property stringList availableBuildVariants: @availableBuildVariants@ + property string qtBuildVariant: { + if (availableBuildVariants.contains(qbs.buildVariant)) + return qbs.buildVariant; + 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 stringList coreLibPaths: @libraryPaths@ + + // 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" + } + + cpp.entryPoint: qbs.targetOS.containsAny(["ios", "tvos"]) + && Utilities.versionCompare(version, "5.6.0") >= 0 + ? "_qt_main_wrapper" + : undefined + cpp.cxxLanguageVersion: Utilities.versionCompare(version, "5.7.0") >= 0 ? "c++11" : original + 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 derived + // from the build variant "release" + if (!qbs.debugInformation) + 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"); + } + return defines; + } + cpp.driverFlags: { + var flags = []; + if (qbs.toolchain.contains("gcc")) { + if (config.contains("sanitize_address")) + flags.push("-fsanitize=address"); + 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: { + var paths = @includes@; + paths.push(mkspecPath, generatedHeadersDir); + return paths; + } + 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.frameworkPaths: 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: qbs.targetOS.contains('linux') ? [libPath] : undefined + cpp.runtimeLibrary: qbs.toolchain.contains("msvc") + ? config.contains("static_runtime") ? "static" : "dynamic" + : original + cpp.positionIndependentCode: versionMajor >= 5 ? true : undefined + cpp.cxxFlags: { + var flags = []; + if (qbs.toolchain.contains('msvc')) { + if (versionMajor < 5) + flags.push('/Zc:wchar_t-'); + } + + return flags; + } + cpp.cxxStandardLibrary: { + if (qbs.targetOS.contains('darwin') && qbs.toolchain.contains('clang') + && config.contains('c++11')) + return "libc++"; + return original; + } + cpp.minimumWindowsVersion: @minWinVersion@ + cpp.minimumMacosVersion: @minMacVersion@ + cpp.minimumIosVersion: @minIosVersion@ + cpp.minimumTvosVersion: @minTvosVersion@ + cpp.minimumWatchosVersion: @minWatchosVersion@ + cpp.minimumAndroidVersion: @minAndroidVersion@ + + // 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"] + + 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 + + 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"] + 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"] + 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"] + } + prepare: { + var cmd = new JavaScriptCommand(); + cmd.description = "creating " + output.fileName; + cmd.highlight = "codegen"; + cmd.sourceCode = function() { + ModUtils.mergeCFiles(inputs["moc_cpp"], output.filePath); + }; + return [cmd]; + } + } + + 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: { + 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]; + } + } + + Rule { + inputs: ["qrc"] + outputFileTags: ["cpp", "cpp_intermediate_object"] + outputArtifacts: { + var artifact = { + filePath: "qrc_" + input.completeBaseName + ".cpp", + fileTags: ["cpp"] + }; + if (input.Qt.core.enableBigResources) + artifact.fileTags.push("cpp_intermediate_object"); + return [artifact]; + } + prepare: { + var args = [input.filePath, + "-name", FileInfo.completeBaseName(input.filePath), + "-o", output.filePath]; + if (input.Qt.core.enableBigResources) + args.push("-pass", "1"); + var cmd = new Command(product.Qt.core.binPath + '/rcc', args); + cmd.description = "rcc " + + (input.Qt.core.enableBigResources ? "(pass 1) " : "") + + input.fileName; + cmd.highlight = 'codegen'; + return cmd; + } + } + + Rule { + inputs: ["intermediate_obj"] + Artifact { + filePath: input.completeBaseName + ".2.o" + fileTags: ["obj"] + } + prepare: { + 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(product.Qt.core.binPath + '/rcc', + [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; + } + } + + 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: { + 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; + } + } + + Rule { + inputs: "qdocconf-main" + explicitlyDependsOn: ["qdoc", "qdocconf"] + + outputFileTags: ModUtils.allFileTags(Qdoc.qdocFileTaggers()) + outputArtifacts: Qdoc.outputArtifacts(product, input) + + prepare: { + var outputDir = product.Qt.core.qdocOutputDir; + var args = Qdoc.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; + } + } + + Rule { + inputs: "qhp" + auxiliaryInputs: ModUtils.allFileTags(Qdoc.qdocFileTaggers()) + .filter(function(tag) { return tag !== "qhp"; }) + + Artifact { + filePath: input.completeBaseName + ".qch" + fileTags: ["qch"] + } + + prepare: { + 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.binPath + "/qhelpgenerator", args); + cmd.description = 'qhelpgenerator ' + input.fileName; + cmd.highlight = 'filegen'; + cmd.stdoutFilterFunction = function(output) { + return ""; + }; + return cmd; + } + } + + @additionalContent@ +} diff --git a/share/qbs/module-providers/Qt/templates/dbus.js b/share/qbs/module-providers/Qt/templates/dbus.js new file mode 100644 index 000000000..0674bf684 --- /dev/null +++ b/share/qbs/module-providers/Qt/templates/dbus.js @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** 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"); + +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]; +} diff --git a/share/qbs/module-providers/Qt/templates/dbus.qbs b/share/qbs/module-providers/Qt/templates/dbus.qbs new file mode 100644 index 000000000..6556e2c9b --- /dev/null +++ b/share/qbs/module-providers/Qt/templates/dbus.qbs @@ -0,0 +1,74 @@ +import qbs.FileInfo +import qbs.ModUtils +import "../QtModule.qbs" as QtModule +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"] + } + + prepare: { + return 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"] + } + + prepare: { + return DBus.createCommands(product, input, outputs, "-p"); + } + } + + 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.includePaths: @includes@ + cpp.libraryPaths: @libraryPaths@ + + @additionalContent@ +} + diff --git a/share/qbs/module-providers/Qt/templates/gui.qbs b/share/qbs/module-providers/Qt/templates/gui.qbs new file mode 100644 index 000000000..eb69e0cad --- /dev/null +++ b/share/qbs/module-providers/Qt/templates/gui.qbs @@ -0,0 +1,65 @@ +import qbs.FileInfo +import qbs.ModUtils +import '../QtModule.qbs' as QtModule + +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"] + } + + prepare: { + var cmd = new Command(ModUtils.moduleProperty(product, "binPath") + '/' + + ModUtils.moduleProperty(product, "uicName"), + [input.filePath, '-o', output.filePath]) + cmd.description = 'uic ' + input.fileName; + cmd.highlight = 'codegen'; + return cmd; + } + } + + property string defaultQpaPlugin: @defaultQpaPlugin@ + 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.defines: @defines@ + cpp.includePaths: @includes@ + cpp.libraryPaths: @libraryPaths@ + + Properties { + condition: Qt.core.staticBuild && qbs.targetOS.contains("ios") + cpp.frameworks: base.concat(["UIKit", "QuartzCore", "CoreText", "CoreGraphics", + "Foundation", "CoreFoundation", "AudioToolbox"]) + } + cpp.frameworks: base + @additionalContent@ +} + diff --git a/share/qbs/module-providers/Qt/templates/moc.js b/share/qbs/module-providers/Qt/templates/moc.js new file mode 100644 index 000000000..aa67766b9 --- /dev/null +++ b/share/qbs/module-providers/Qt/templates/moc.js @@ -0,0 +1,102 @@ +/**************************************************************************** +** +** 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"); + +function args(product, input, outputFileName) +{ + var defines = product.cpp.compilerDefinesByLanguage; + if (input.fileTags.contains("objcpp")) + defines = ModUtils.flattenDictionary(defines["objcpp"]) || []; + else if (input.fileTags.contains("cpp")) + 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 = []; + 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) +{ + return product.Qt.core.binPath + '/' + 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"); + } + return [artifact]; +} + +function commands(project, product, inputs, outputs, input, output) +{ + var cmd = new Command(fullPath(product), args(product, input, output.filePath)); + cmd.description = 'moc ' + input.fileName; + cmd.highlight = 'codegen'; + return cmd; +} diff --git a/share/qbs/module-providers/Qt/templates/module.qbs b/share/qbs/module-providers/Qt/templates/module.qbs new file mode 100644 index 000000000..b09f79a87 --- /dev/null +++ b/share/qbs/module-providers/Qt/templates/module.qbs @@ -0,0 +1,30 @@ +import '../QtModule.qbs' as QtModule + +QtModule { + qtModuleName: @name@ + Depends { name: "Qt"; submodules: @dependencies@} + + 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.includePaths: @includes@ + cpp.libraryPaths: @libraryPaths@ + @additionalContent@ +} diff --git a/share/qbs/module-providers/Qt/templates/plugin.qbs b/share/qbs/module-providers/Qt/templates/plugin.qbs new file mode 100644 index 000000000..e73e2a4d9 --- /dev/null +++ b/share/qbs/module-providers/Qt/templates/plugin.qbs @@ -0,0 +1,27 @@ +import '../QtPlugin.qbs' as QtPlugin + +QtPlugin { + qtModuleName: @name@ + Depends { name: "Qt"; submodules: @dependencies@} + + 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@ +} diff --git a/share/qbs/module-providers/Qt/templates/plugin_support.qbs b/share/qbs/module-providers/Qt/templates/plugin_support.qbs new file mode 100644 index 000000000..13d95c383 --- /dev/null +++ b/share/qbs/module-providers/Qt/templates/plugin_support.qbs @@ -0,0 +1,75 @@ +Module { + // Set by user. + property varList pluginsByType + + // 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 (!Array.isArray(newValue)) + 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."; + } + } + } + } + } +} diff --git a/share/qbs/module-providers/Qt/templates/qdoc.js b/share/qbs/module-providers/Qt/templates/qdoc.js new file mode 100644 index 000000000..72c161c56 --- /dev/null +++ b/share/qbs/module-providers/Qt/templates/qdoc.js @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** 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")); +} diff --git a/share/qbs/module-providers/Qt/templates/qml.js b/share/qbs/module-providers/Qt/templates/qml.js new file mode 100644 index 000000000..c7829d81b --- /dev/null +++ b/share/qbs/module-providers/Qt/templates/qml.js @@ -0,0 +1,66 @@ +var File = require("qbs.File"); +var FileInfo = require("qbs.FileInfo"); +var Process = require("qbs.Process"); +var TextFile = require("qbs.TextFile"); + +function scannerData(scannerFilePath, qmlFiles, qmlPath) +{ + var p; + try { + p = new Process(); + p.exec(scannerFilePath, ["-qmlFiles"].concat(qmlFiles).concat(["-importPath", qmlPath]), + true); + return JSON.parse(p.readStdOut()); + } finally { + if (p) + p.close(); + } +} + +function getPrlRhs(line) +{ + return line.split('=')[1].trim(); +} + +function getLibsForPlugin(pluginData, buildVariant, targetOS, toolchain, qtLibDir) +{ + if (!pluginData.path) + return ""; + var prlFileName = ""; + if (!targetOS.contains("windows")) + prlFileName += "lib"; + prlFileName += pluginData.plugin; + if (buildVariant === "debug" && targetOS.contains("windows")) + prlFileName += "d"; + 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 (line = prlFile.readLine()) { + 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); + otherLibs += otherLibsLine; + } + } + if (!pluginLib) + throw "Malformed prl file '" + prlFilePath + "'."; + return pluginLib + ' ' + otherLibs; + } finally { + prlFile.close(); + } +} diff --git a/share/qbs/module-providers/Qt/templates/qml.qbs b/share/qbs/module-providers/Qt/templates/qml.qbs new file mode 100644 index 000000000..2b11abbd5 --- /dev/null +++ b/share/qbs/module-providers/Qt/templates/qml.qbs @@ -0,0 +1,132 @@ +import qbs.TextFile +import '../QtModule.qbs' as QtModule +import "qml.js" as Qml + +QtModule { + qtModuleName: "Qml" + Depends { name: "Qt"; submodules: @dependencies@} + + property string qmlImportScannerName: "qmlimportscanner" + property string qmlImportScannerFilePath: Qt.core.binPath + '/' + qmlImportScannerName + 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" + + hasLibrary: @has_library@ + architectures: @archs@ + targetPlatform: @targetPlatform@ + staticLibsDebug: (isStaticLibrary ? ['@' + pluginListFilePathDebug] : []).concat(@staticLibsDebug@) + staticLibsRelease: (isStaticLibrary ? ['@' + 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.includePaths: @includes@ + cpp.libraryPaths: @libraryPaths@ + @additionalContent@ + + FileTagger { + patterns: ["*.qml"] + fileTags: ["qt.qml.qml"] + } + + FileTagger { + patterns: ["*.js"] + fileTags: ["qt.qml.js"] + } + + Rule { + condition: isStaticLibrary + multiplex: true + requiresInputs: false + inputs: ["qt.qml.qml"] + outputFileTags: ["cpp", "qt.qml.pluginlist"] + outputArtifacts: { + 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; + } + prepare: { + 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); + 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 = { }; + 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.Qt.core.qtBuildVariant, + product.qbs.targetOS, + product.qbs.toolchain, + product.Qt.core.libPath); + listFile.write(libs + ' '); + } + } finally { + if (cppFile) + cppFile.close(); + if (listFile) + listFile.close(); + }; + }; + return [cmd]; + } + } +} diff --git a/share/qbs/module-providers/Qt/templates/qmlcache.qbs b/share/qbs/module-providers/Qt/templates/qmlcache.qbs new file mode 100644 index 000000000..9111eb500 --- /dev/null +++ b/share/qbs/module-providers/Qt/templates/qmlcache.qbs @@ -0,0 +1,85 @@ +import 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.binPath, "qmlcachegen") + + (qbs.hostOS.contains("windows") ? ".exe" : "") + 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 + } +} diff --git a/share/qbs/module-providers/Qt/templates/quick.js b/share/qbs/module-providers/Qt/templates/quick.js new file mode 100644 index 000000000..4f3da2fb0 --- /dev/null +++ b/share/qbs/module-providers/Qt/templates/quick.js @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** 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"); + +function scanQrc(qrcFilePath) { + var absInputDir = FileInfo.path(qrcFilePath); + var result = []; + var process = new Process(); + try { + var rcc = FileInfo.joinPaths(product.Qt.core.binPath, 'rcc' + product.cpp.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(qrcFilePath) { + var filesInQrc = scanQrc(qrcFilePath); + var qmlJsFiles = filesInQrc.filter(function (filePath) { + return (/\.(js|qml)$/).test(filePath); + } ); + var content = {}; + if (filesInQrc.length - qmlJsFiles.length > 0) { + content.newQrcFileName = qtQuickResourceFileOutputName(input.fileName); + } + content.qmlJsFiles = qmlJsFiles.map(function (filePath) { + return { + input: filePath, + output: qtQuickCompilerOutputName(filePath) + }; + }); + return content; +} diff --git a/share/qbs/module-providers/Qt/templates/quick.qbs b/share/qbs/module-providers/Qt/templates/quick.qbs new file mode 100644 index 000000000..5968949c8 --- /dev/null +++ b/share/qbs/module-providers/Qt/templates/quick.qbs @@ -0,0 +1,211 @@ +/**************************************************************************** +** +** 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.TextFile +import qbs.Utilities +import '../QtModule.qbs' as QtModule +import 'quick.js' as QC + +QtModule { + qtModuleName: @name@ + Depends { name: "Qt"; submodules: @dependencies@.concat("qml-private") } + + 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.includePaths: @includes@ + cpp.libraryPaths: @libraryPaths@ + @additionalContent@ + + readonly property bool _compilerIsQmlCacheGen: Utilities.versionCompare(Qt.core.version, + "5.11") >= 0 + readonly property string _generatedLoaderFileName: _compilerIsQmlCacheGen + ? "qmlcache_loader.cpp" + : "qtquickcompiler_loader.cpp" + property string compilerBaseName: (_compilerIsQmlCacheGen ? "qmlcachegen" : "qtquickcompiler") + property string compilerFilePath: FileInfo.joinPaths(Qt.core.binPath, + compilerBaseName + product.cpp.executableSuffix) + property bool compilerAvailable: File.exists(compilerFilePath); + property bool useCompiler: compilerAvailable && !_compilerIsQmlCacheGen + + Scanner { + condition: useCompiler + inputs: 'qt.quick.qrc' + searchPaths: [FileInfo.path(input.filePath)] + scan: QC.scanQrc(input.filePath) + } + + FileTagger { + condition: useCompiler + patterns: "*.qrc" + fileTags: ["qt.quick.qrc"] + priority: 100 + } + + Rule { + condition: useCompiler + inputs: ["qt.quick.qrc"] + Artifact { + filePath: input.fileName + ".json" + fileTags: ["qt.quick.qrcinfo"] + } + prepare: { + var cmd = new JavaScriptCommand(); + cmd.silent = true; + cmd.sourceCode = function() { + var content = QC.contentFromQrc(input.filePath); + content.qrcFilePath = input.filePath; + + var tf = new TextFile(output.filePath, TextFile.WriteOnly); + tf.write(JSON.stringify(content)); + tf.close(); + } + return cmd; + } + } + + Rule { + condition: useCompiler + inputs: ["qt.quick.qrcinfo"] + outputFileTags: ["cpp", "qrc"] + multiplex: true + outputArtifacts: { + 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; + } + prepare: { + 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); + 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; + } + } +} diff --git a/share/qbs/module-providers/Qt/templates/scxml.qbs b/share/qbs/module-providers/Qt/templates/scxml.qbs new file mode 100644 index 000000000..7125ec53c --- /dev/null +++ b/share/qbs/module-providers/Qt/templates/scxml.qbs @@ -0,0 +1,80 @@ +import qbs.FileInfo +import qbs.Utilities +import "../QtModule.qbs" as QtModule + +QtModule { + qtModuleName: "Scxml" + + 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"] + } + + prepare: { + var compilerName = product.moduleProperty("Qt.scxml", "qscxmlcName"); + var compilerPath = FileInfo.joinPaths(input.moduleProperty("Qt.core", "binPath"), + 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]; + } + } + + 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.includePaths: @includes@ + cpp.libraryPaths: @libraryPaths@ + + @additionalContent@ +} diff --git a/src/app/qbs-setup-android/android-setup.cpp b/src/app/qbs-setup-android/android-setup.cpp index d32cdbc05..8c7373652 100644 --- a/src/app/qbs-setup-android/android-setup.cpp +++ b/src/app/qbs-setup-android/android-setup.cpp @@ -224,7 +224,7 @@ static void setupNdk(qbs::Settings *settings, const QString &profileName, const mainProfile.setValue(qls("qbs.architecture"), archsForProfile.front()); else mainProfile.setValue(qls("qbs.architectures"), archsForProfile); - QStringList searchPaths; + QStringList qmakeFilePaths; QString platform; for (const QString &arch : archs) { const QtAndroidInfo qtAndroidInfo = infoPerArch.value(arch); @@ -248,11 +248,11 @@ static void setupNdk(qbs::Settings *settings, const QString &profileName, const } settings->sync(); qbs::Internal::TemporaryProfile p(subProName, settings); - searchPaths << p.p.value(qls("preferences.qbsSearchPaths")).toStringList(); + qmakeFilePaths << p.p.value(qls("moduleProviders.Qt.qmakeFilePaths")).toStringList(); platform = maximumPlatform(platform, qtAndroidInfo.platform); } - if (!searchPaths.empty()) - mainProfile.setValue(qls("preferences.qbsSearchPaths"), searchPaths); + if (!qmakeFilePaths.empty()) + mainProfile.setValue(qls("moduleProviders.Qt.qmakeFilePaths"), qmakeFilePaths); if (!platform.isEmpty()) mainProfile.setValue(qls("Android.ndk.platform"), platform); } diff --git a/src/app/qbs-setup-qt/main.cpp b/src/app/qbs-setup-qt/main.cpp index d1bfd9614..94185c4d7 100644 --- a/src/app/qbs-setup-qt/main.cpp +++ b/src/app/qbs-setup-qt/main.cpp @@ -40,7 +40,6 @@ #include "commandlineparser.h" -#include #include #include @@ -72,16 +71,16 @@ int main(int argc, char *argv[]) if (clParser.autoDetectionMode()) { // search all Qt's in path and dump their settings - const std::vector qtEnvironments = SetupQt::fetchEnvironments(); + 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 EnhancedQtEnvironment &qtEnvironment : qtEnvironments) { - QString profileName = QLatin1String("qt-") + qtEnvironment.qtVersion; + for (const QtEnvironment &qtEnvironment : qtEnvironments) { + QString profileName = QLatin1String("qt-") + qtEnvironment.qtVersion.toString(); if (SetupQt::checkIfMoreThanOneQtWithTheSameVersion(qtEnvironment.qtVersion, qtEnvironments)) { - QStringList prefixPathParts = qtEnvironment.installPrefixPath + QStringList prefixPathParts = QFileInfo(qtEnvironment.qmakeFilePath).path() .split(QLatin1Char('/'), QString::SkipEmptyParts); if (!prefixPathParts.empty()) profileName += QLatin1String("-") + prefixPathParts.last(); @@ -97,7 +96,7 @@ int main(int argc, char *argv[]) return EXIT_FAILURE; } - EnhancedQtEnvironment qtEnvironment = SetupQt::fetchEnvironment(clParser.qmakePath()); + const QtEnvironment qtEnvironment = SetupQt::fetchEnvironment(clParser.qmakePath()); QString profileName = clParser.profileName(); profileName.replace(QLatin1Char('.'), QLatin1Char('-')); SetupQt::saveToQbsSettings(profileName, qtEnvironment, &settings); diff --git a/src/app/qbs-setup-qt/qbs-setup-qt.pro b/src/app/qbs-setup-qt/qbs-setup-qt.pro index 036a4e74c..a5694d6b7 100644 --- a/src/app/qbs-setup-qt/qbs-setup-qt.pro +++ b/src/app/qbs-setup-qt/qbs-setup-qt.pro @@ -1,5 +1,4 @@ include(../app.pri) -include($${PWD}/../../lib/qtprofilesetup/use_qtprofilesetup.pri) TARGET = qbs-setup-qt diff --git a/src/app/qbs-setup-qt/qbs-setup-qt.qbs b/src/app/qbs-setup-qt/qbs-setup-qt.qbs index 8bd4ae263..f4cd9d6b8 100644 --- a/src/app/qbs-setup-qt/qbs-setup-qt.qbs +++ b/src/app/qbs-setup-qt/qbs-setup-qt.qbs @@ -2,7 +2,6 @@ import qbs 1.0 QbsApp { name: "qbs-setup-qt" - Depends { name: "qbsqtprofilesetup" } files: [ "commandlineparser.cpp", "commandlineparser.h", diff --git a/src/app/qbs-setup-qt/setupqt.cpp b/src/app/qbs-setup-qt/setupqt.cpp index f54411b48..d4a59e30b 100644 --- a/src/app/qbs-setup-qt/setupqt.cpp +++ b/src/app/qbs-setup-qt/setupqt.cpp @@ -40,8 +40,6 @@ #include "setupqt.h" #include "../shared/logging/consolelogger.h" -#include -#include #include #include #include @@ -56,10 +54,10 @@ #include #include #include -#include #include #include +#include namespace qbs { using Internal::none_of; @@ -105,210 +103,91 @@ bool SetupQt::isQMakePathValid(const QString &qmakePath) return qmakeFileInfo.exists() && qmakeFileInfo.isFile() && qmakeFileInfo.isExecutable(); } -std::vector SetupQt::fetchEnvironments() +std::vector SetupQt::fetchEnvironments() { - std::vector qtEnvironments; - + std::vector qtEnvironments; const auto qmakePaths = collectQmakePaths(); for (const QString &qmakePath : qmakePaths) { - const EnhancedQtEnvironment env = fetchEnvironment(qmakePath); - if (none_of(qtEnvironments, [&env](const EnhancedQtEnvironment &otherEnv) { - return env.includePath == otherEnv.includePath; + const QtEnvironment env = fetchEnvironment(qmakePath); + if (none_of(qtEnvironments, [&env](const QtEnvironment &otherEnv) { + return env.qmakeFilePath == otherEnv.qmakeFilePath; })) { qtEnvironments.push_back(env); } } - return qtEnvironments; } -void SetupQt::addQtBuildVariant(QtEnvironment *env, const QString &buildVariantName) +// These functions work only for Qt from installer. +static QStringList qbsToolchainFromDirName(const QString &dir) { - if (env->qtConfigItems.contains(buildVariantName)) - env->buildVariant << buildVariantName; + if (dir.startsWith(QLatin1String("msvc"))) + return QStringList(QLatin1String("msvc")); + if (dir.startsWith(QLatin1String("mingw"))) + return QStringList{QLatin1String("mingw"), QLatin1String("gcc")}; + if (dir.startsWith(QLatin1String("clang"))) + return QStringList{QLatin1String("clang"), QLatin1String("llvm"), QLatin1String("gcc")}; + if (dir.startsWith(QLatin1String("gcc"))) + return QStringList(QLatin1String("gcc")); + return QStringList(); } -static QMap qmakeQueryOutput(const QString &qmakePath) +static Version msvcVersionFromDirName(const QString &dir) { - QProcess qmakeProcess; - qmakeProcess.start(qmakePath, QStringList() << QLatin1String("-query")); - if (!qmakeProcess.waitForStarted()) - throw ErrorInfo(SetupQt::tr("%1 cannot be started.").arg(qmakePath)); - qmakeProcess.waitForFinished(); - const QByteArray output = qmakeProcess.readAllStandardOutput(); - - QMap ret; - const auto lines = output.split('\n'); - for (const QByteArray &line : lines) { - int idx = line.indexOf(':'); - if (idx >= 0) - ret[line.left(idx)] = line.mid(idx + 1).trimmed(); - } - return ret; + 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(); + QMap mapping{ + std::make_pair("2005", "14"), std::make_pair("2008", "15"), std::make_pair("2010", "16"), + std::make_pair("2012", "17"), std::make_pair("2013", "18"), std::make_pair("2015", "19"), + std::make_pair("2017", "19.1") + }; + return Version::fromString(QString::fromStdString(mapping.value(match[1].str()))); } -static QByteArray readFileContent(const QString &filePath) +static QString archFromDirName(const QString &dir) { - QFile file(filePath); - if (file.open(QFile::ReadOnly)) - return file.readAll(); - - return QByteArray(); + static const std::regex regexp("^[^_]+_(.*).*$"); + std::smatch match; + const std::string dirString = dir.toStdString(); + if (!std::regex_match(dirString, match, regexp)) + return QString(); + const QString arch = QString::fromStdString(match[1]); + if (arch == QLatin1String("32")) + return QLatin1String("x86"); + if (arch == QLatin1String("64")) + return QLatin1String("x86_64"); + if (arch.contains(QLatin1String("arm64"))) + return QLatin1String("arm64"); + return arch; } -static QString configVariable(const QByteArray &configContent, const QString &key) +static QString platformFromDirName(const QString &dir) { - QRegExp regexp(QLatin1String("\\s*") + key + QLatin1String("\\s*\\+{0,1}=(.*)"), - Qt::CaseSensitive); - - const QList configContentLines = configContent.split('\n'); - - bool success = false; - - for (const QByteArray &configContentLine : configContentLines) { - success = regexp.exactMatch(QString::fromLocal8Bit(configContentLine)); - if (success) - break; - } - - if (success) - return regexp.capturedTexts()[1].simplified(); - - return QString(); -} - -static QStringList configVariableItems(const QByteArray &configContent, const QString &key) -{ - return configVariable(configContent, key).split(QLatin1Char(' '), QString::SkipEmptyParts); -} - -typedef QMap QueryMap; - -static QString pathQueryValue(const QueryMap &queryMap, const QByteArray &key) -{ - return QDir::fromNativeSeparators(QString::fromLocal8Bit(queryMap.value(key))); + if (dir.startsWith(QLatin1String("android"))) + return QLatin1String("android"); + if (dir == QLatin1String("Boot2Qt")) + return QLatin1String("linux"); + return QString::fromStdString(HostOsInfo::hostOSIdentifier()); } -EnhancedQtEnvironment SetupQt::fetchEnvironment(const QString &qmakePath) +QtEnvironment SetupQt::fetchEnvironment(const QString &qmakePath) { - EnhancedQtEnvironment qtEnvironment; - QueryMap queryOutput = qmakeQueryOutput(qmakePath); - - qtEnvironment.installPrefixPath = pathQueryValue(queryOutput, "QT_INSTALL_PREFIX"); - qtEnvironment.documentationPath = pathQueryValue(queryOutput, "QT_INSTALL_DOCS"); - qtEnvironment.includePath = pathQueryValue(queryOutput, "QT_INSTALL_HEADERS"); - qtEnvironment.libraryPath = pathQueryValue(queryOutput, "QT_INSTALL_LIBS"); - qtEnvironment.binaryPath = pathQueryValue(queryOutput, "QT_HOST_BINS"); - if (qtEnvironment.binaryPath.isEmpty()) - qtEnvironment.binaryPath = pathQueryValue(queryOutput, "QT_INSTALL_BINS"); - qtEnvironment.documentationPath = pathQueryValue(queryOutput, "QT_INSTALL_DOCS"); - qtEnvironment.pluginPath = pathQueryValue(queryOutput, "QT_INSTALL_PLUGINS"); - qtEnvironment.qmlPath = pathQueryValue(queryOutput, "QT_INSTALL_QML"); - qtEnvironment.qmlImportPath = pathQueryValue(queryOutput, "QT_INSTALL_IMPORTS"); - qtEnvironment.qtVersion = QString::fromLocal8Bit(queryOutput.value("QT_VERSION")); - - const Version qtVersion = Version::fromString(qtEnvironment.qtVersion); - - QString mkspecsBaseSrcPath; - if (qtVersion.majorVersion() >= 5) { - qtEnvironment.mkspecBasePath - = pathQueryValue(queryOutput, "QT_HOST_DATA") + QLatin1String("/mkspecs"); - mkspecsBaseSrcPath - = pathQueryValue(queryOutput, "QT_HOST_DATA/src") + QLatin1String("/mkspecs"); - } else { - qtEnvironment.mkspecBasePath - = pathQueryValue(queryOutput, "QT_INSTALL_DATA") + QLatin1String("/mkspecs"); - } - - if (!QFile::exists(qtEnvironment.mkspecBasePath)) - throw ErrorInfo(tr("Cannot extract the mkspecs directory.")); - - const QByteArray qconfigContent = readFileContent(qtEnvironment.mkspecBasePath - + QLatin1String("/qconfig.pri")); - qtEnvironment.qtMajorVersion = configVariable(qconfigContent, - QLatin1String("QT_MAJOR_VERSION")).toInt(); - qtEnvironment.qtMinorVersion = configVariable(qconfigContent, - QLatin1String("QT_MINOR_VERSION")).toInt(); - qtEnvironment.qtPatchVersion = configVariable(qconfigContent, - QLatin1String("QT_PATCH_VERSION")).toInt(); - qtEnvironment.qtNameSpace = configVariable(qconfigContent, QLatin1String("QT_NAMESPACE")); - qtEnvironment.qtLibInfix = configVariable(qconfigContent, QLatin1String("QT_LIBINFIX")); - qtEnvironment.architecture = configVariable(qconfigContent, QLatin1String("QT_TARGET_ARCH")); - if (qtEnvironment.architecture.isEmpty()) - qtEnvironment.architecture = configVariable(qconfigContent, QLatin1String("QT_ARCH")); - if (qtEnvironment.architecture.isEmpty()) - qtEnvironment.architecture = QLatin1String("x86"); - qtEnvironment.configItems = configVariableItems(qconfigContent, QLatin1String("CONFIG")); - qtEnvironment.qtConfigItems = configVariableItems(qconfigContent, QLatin1String("QT_CONFIG")); - - // retrieve the mkspec - if (qtVersion.majorVersion() >= 5) { - const QString mkspecName = QString::fromLocal8Bit(queryOutput.value("QMAKE_XSPEC")); - qtEnvironment.mkspecName = mkspecName; - qtEnvironment.mkspecPath = qtEnvironment.mkspecBasePath + QLatin1Char('/') + mkspecName; - if (!mkspecsBaseSrcPath.isEmpty() && !QFile::exists(qtEnvironment.mkspecPath)) - qtEnvironment.mkspecPath = mkspecsBaseSrcPath + QLatin1Char('/') + mkspecName; - } else { - if (HostOsInfo::isWindowsHost()) { - const QString baseDirPath = qtEnvironment.mkspecBasePath + QLatin1String("/default/"); - const QByteArray fileContent = readFileContent(baseDirPath - + QLatin1String("qmake.conf")); - qtEnvironment.mkspecPath = configVariable(fileContent, - QLatin1String("QMAKESPEC_ORIGINAL")); - if (!QFile::exists(qtEnvironment.mkspecPath)) { - // Work around QTBUG-28792. - // The value of QMAKESPEC_ORIGINAL is wrong for MinGW packages. Y u h8 me? - const QRegExp rex(QLatin1String("\\binclude\\(([^)]+)/qmake\\.conf\\)")); - if (rex.indexIn(QString::fromLocal8Bit(fileContent)) != -1) - qtEnvironment.mkspecPath = QDir::cleanPath(baseDirPath + rex.cap(1)); - } - } else { - qtEnvironment.mkspecPath = QFileInfo(qtEnvironment.mkspecBasePath - + QLatin1String("/default")).symLinkTarget(); - } - - // 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++ - qtEnvironment.mkspecPath = QDir::cleanPath(qtEnvironment.mkspecPath); - - qtEnvironment.mkspecName = qtEnvironment.mkspecPath; - int idx = qtEnvironment.mkspecName.lastIndexOf(QLatin1Char('/')); - if (idx != -1) - qtEnvironment.mkspecName.remove(0, idx + 1); + QtEnvironment env; + env.qmakeFilePath = qmakePath; + QDir qtDir = QFileInfo(qmakePath).dir(); + if (qtDir.dirName() == QLatin1String("bin")) { + qtDir.cdUp(); + env.qbsToolchain = qbsToolchainFromDirName(qtDir.dirName()); + env.msvcVersion = msvcVersionFromDirName(qtDir.dirName()); + env.architecture = archFromDirName(qtDir.dirName()); + env.targetPlatform = platformFromDirName(qtDir.dirName()); + qtDir.cdUp(); + env.qtVersion = Version::fromString(qtDir.dirName()); } - - // determine MSVC version - if (isMsvcQt(qtEnvironment)) { - bool ok; - qtEnvironment.msvcVersion.setMajorVersion( - configVariable(qconfigContent, - QLatin1String("QT_MSVC_MAJOR_VERSION")).toInt(&ok)); - if (ok) { - qtEnvironment.msvcVersion.setMinorVersion( - configVariable(qconfigContent, - QLatin1String("QT_MSVC_MINOR_VERSION")).toInt(&ok)); - } - if (ok) { - qtEnvironment.msvcVersion.setPatchLevel( - configVariable(qconfigContent, - QLatin1String("QT_MSVC_PATCH_VERSION")).toInt(&ok)); - } - if (!ok) - qtEnvironment.msvcVersion = msvcCompilerVersionFromMkspecName(qtEnvironment.mkspecName); - } - - // determine whether we have a framework build - qtEnvironment.frameworkBuild = qtEnvironment.mkspecPath.contains(QLatin1String("macx")) - && qtEnvironment.configItems.contains(QLatin1String("qt_framework")); - - // determine whether Qt is built with debug, release or both - addQtBuildVariant(&qtEnvironment, QLatin1String("debug")); - addQtBuildVariant(&qtEnvironment, QLatin1String("release")); - - if (!QFileInfo(qtEnvironment.mkspecPath).exists()) - throw ErrorInfo(tr("mkspec '%1' does not exist").arg(qtEnvironment.mkspecPath)); - - return qtEnvironment; + return env; } static bool isToolchainProfile(const Profile &profile) @@ -323,6 +202,12 @@ static bool isToolchainProfile(const Profile &profile) 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 std::any_of(searchPaths.cbegin(), searchPaths.cend(), [] (const QString &path) { @@ -337,39 +222,18 @@ template bool areProfilePropertiesIncompatible(const T &set1, const return set1.size() > 0 && set2.size() > 0 && set1 != set2; } -static QStringList qbsToolchainFromQtMkspec(const QtEnvironment &qtEnv) -{ - const QString mkspec = qtEnv.mkspecName; - if (mkspec.contains(QLatin1String("-msvc"))) - return QStringList() << QLatin1String("msvc"); - if (qtEnv.isForMinGw()) - return QStringList() << QLatin1String("mingw") << QLatin1String("gcc"); - - if (mkspec.contains(QLatin1String("-clang"))) - return QStringList() << QLatin1String("clang") << QLatin1String("llvm") - << QLatin1String("gcc"); - if (mkspec.contains(QLatin1String("-llvm"))) - return QStringList() << QLatin1String("llvm") << QLatin1String("gcc"); - if (mkspec.contains(QLatin1String("-g++"))) - return QStringList() << QLatin1String("gcc"); - - // Worry about other, less common toolchains (ICC, QCC, etc.) later... - return QStringList(); -} - enum Match { MatchFull, MatchPartial, MatchNone }; -static Match compatibility(const EnhancedQtEnvironment &env, const Profile &toolchainProfile) +static Match compatibility(const QtEnvironment &env, const Profile &toolchainProfile) { Match match = MatchFull; const auto toolchainNames = Internal::Set::fromList( toolchainProfile.value(QLatin1String("qbs.toolchain")).toStringList()); - const auto mkspecToolchainNames = Internal::Set::fromList( - qbsToolchainFromQtMkspec(env)); - if (areProfilePropertiesIncompatible(toolchainNames, mkspecToolchainNames)) { + const auto qtToolchainNames = Internal::Set::fromList(env.qbsToolchain); + if (areProfilePropertiesIncompatible(toolchainNames, qtToolchainNames)) { auto intersection = toolchainNames; - intersection.intersect(mkspecToolchainNames); + intersection.intersect(qtToolchainNames); if (!intersection.empty()) match = MatchPartial; else @@ -378,7 +242,7 @@ static Match compatibility(const EnhancedQtEnvironment &env, const Profile &tool const auto targetPlatform = toolchainProfile.value( QLatin1String("qbs.targetPlatform")).toString(); - if (!targetPlatform.isEmpty() && targetPlatform != qbsTargetPlatformFromQtMkspec(env)) + if (!targetPlatform.isEmpty() && targetPlatform != env.targetPlatform) return MatchNone; const QString toolchainArchitecture = toolchainProfile.value(QLatin1String("qbs.architecture")) @@ -438,7 +302,7 @@ static void compressMsvcProfiles(QStringList &profiles) } void SetupQt::saveToQbsSettings(const QString &qtVersionName, - const EnhancedQtEnvironment &qtEnvironment, + const QtEnvironment &qtEnvironment, Settings *settings) { const QString cleanQtVersionName = Profile::cleanName(qtVersionName); @@ -446,14 +310,10 @@ void SetupQt::saveToQbsSettings(const QString &qtVersionName, .arg(cleanQtVersionName); printf("%s\n", qPrintable(msg)); - const ErrorInfo errorInfo = setupQtProfile(cleanQtVersionName, settings, qtEnvironment); - if (errorInfo.hasError()) - throw errorInfo; - - // If this profile does not specify a toolchain and we find exactly one profile that looks - // like it might have been added by qbs-setup-toolchains, let's use that one as our - // base profile. Profile profile(cleanQtVersionName, settings); + profile.removeProfile(); + profile.setValue(QLatin1String("moduleProviders.Qt.qmakeFilePaths"), + QStringList(qtEnvironment.qmakeFilePath)); if (!profile.baseProfile().isEmpty()) return; if (isToolchainProfile(profile)) @@ -490,19 +350,14 @@ void SetupQt::saveToQbsSettings(const QString &qtVersionName, else if (fullMatches.empty() && partialMatches.size() == 1) bestMatch = partialMatches.front(); if (bestMatch.isEmpty()) { - QString message = Tr::tr("You need to set up toolchain information before you can " - "use this Qt version for building. "); - if (fullMatches.empty() && partialMatches.empty()) { - message += Tr::tr("However, no toolchain profile was found. Either create one " - "using qbs-setup-toolchains and set it as this profile's " - "base profile or add the toolchain settings manually " - "to this profile."); - } else { + 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(", "))); } - qbsWarning() << message; + qbsInfo() << message; } else { profile.setBaseProfile(bestMatch); qbsInfo() << Tr::tr("Setting profile '%1' as the base profile for this profile.") @@ -510,8 +365,8 @@ void SetupQt::saveToQbsSettings(const QString &qtVersionName, } } -bool SetupQt::checkIfMoreThanOneQtWithTheSameVersion(const QString &qtVersion, - const std::vector &qtEnvironments) +bool SetupQt::checkIfMoreThanOneQtWithTheSameVersion(const Version &qtVersion, + const std::vector &qtEnvironments) { bool foundOneVersion = false; for (const QtEnvironment &qtEnvironment : qtEnvironments) { diff --git a/src/app/qbs-setup-qt/setupqt.h b/src/app/qbs-setup-qt/setupqt.h index 73c0afefe..c10ae637c 100644 --- a/src/app/qbs-setup-qt/setupqt.h +++ b/src/app/qbs-setup-qt/setupqt.h @@ -40,8 +40,8 @@ #ifndef QBS_SETUPQT_H #define QBS_SETUPQT_H -#include #include +#include #include #include @@ -50,27 +50,30 @@ namespace qbs { -class EnhancedQtEnvironment : public QtEnvironment +class Settings; + +class QtEnvironment { public: + QString qmakeFilePath; + QStringList qbsToolchain; + QString architecture; + QString targetPlatform; + Version qtVersion; Version msvcVersion; }; -class Settings; - class SetupQt { Q_DECLARE_TR_FUNCTIONS(SetupQt) public: static bool isQMakePathValid(const QString &qmakePath); - static std::vector fetchEnvironments(); - static void addQtBuildVariant(QtEnvironment *env, const QString &buildVariantName); - static EnhancedQtEnvironment fetchEnvironment(const QString &qmakePath); - static void saveToQbsSettings(const QString &qtVersionName, - const EnhancedQtEnvironment &qtEnvironment, + 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); - static bool checkIfMoreThanOneQtWithTheSameVersion(const QString &qtVersion, - const std::vector &qtEnvironments); }; } // namespace qbs diff --git a/src/lib/corelib/jsextensions/utilitiesextension.cpp b/src/lib/corelib/jsextensions/utilitiesextension.cpp index a10251c54..4cbe6ed2f 100644 --- a/src/lib/corelib/jsextensions/utilitiesextension.cpp +++ b/src/lib/corelib/jsextensions/utilitiesextension.cpp @@ -51,6 +51,26 @@ #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 @@ -58,6 +78,9 @@ #include #include +#include +#include +#include #include #include @@ -91,6 +114,10 @@ public: static QScriptValue js_qmlTypeInfo(QScriptContext *context, QScriptEngine *engine); static QScriptValue js_builtinExtensionNames(QScriptContext *context, QScriptEngine *engine); + static QScriptValue js_isSharedLibrary(QScriptContext *context, QScriptEngine *engine); + + static QScriptValue js_getArchitecturesFromBinary(QScriptContext *context, + QScriptEngine *engine); }; QScriptValue UtilitiesExtension::js_ctor(QScriptContext *context, QScriptEngine *engine) @@ -504,6 +531,237 @@ QScriptValue UtilitiesExtension::js_builtinExtensionNames(QScriptContext *contex return engine->toScriptValue(JsExtensions::extensionNames()); } +QScriptValue UtilitiesExtension::js_isSharedLibrary(QScriptContext *context, QScriptEngine *engine) +{ + if (context->argumentCount() == 1) { + const QScriptValue value = context->argument(0); + if (value.isString()) + return engine->toScriptValue(QLibrary::isLibrary(value.toString())); + } + return context->throwError(QScriptContext::SyntaxError, + QStringLiteral("isSharedLibrary expects one argument of type string")); +} + +#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 QString(); + } + 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 QString(); + } + 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 QString(); + } + case CPU_TYPE_ARM64: + switch (cpusubtype) { + case CPU_SUBTYPE_ARM64_ALL: + return QStringLiteral("arm64"); + default: + return QString(); + } + default: + return QString(); + } +} + +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 QStringList(); + + 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(); + + 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 QStringList(); + + 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 QStringList(); + } + 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 QStringList(); + + 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 QStringList(); + } + + header.cputype = static_cast(readInt(device, &ok, swap)); + if (!ok) + return QStringList(); + + header.cpusubtype = static_cast(readInt(device, &ok, swap)); + if (!ok) + return QStringList(); + + 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 + +QScriptValue UtilitiesExtension::js_getArchitecturesFromBinary(QScriptContext *context, + QScriptEngine *engine) +{ + if (context->argumentCount() != 1) { + return context->throwError(QScriptContext::SyntaxError, + QStringLiteral("getArchitecturesFromBinary expects exactly one argument")); + } + const QScriptValue arg = context->argument(0); + if (!arg.isString()) { + return context->throwError(QScriptContext::SyntaxError, + QStringLiteral("getArchitecturesFromBinary expects a string argument")); + } + QStringList archs; +#ifdef __APPLE__ + QFile file(arg.toString()); + if (!file.open(QIODevice::ReadOnly)) { + return context->throwError(QScriptContext::SyntaxError, + QStringLiteral("Failed to open file '%1': %2") + .arg(file.fileName(), file.errorString())); + } + archs = detectMachOArchs(&file); +#endif // __APPLE__ + return engine->toScriptValue(archs); +} + } // namespace Internal } // namespace qbs @@ -548,6 +806,10 @@ void initializeJsExtensionUtilities(QScriptValue extensionObject) engine->newFunction(UtilitiesExtension::js_qmlTypeInfo, 0)); environmentObj.setProperty(QStringLiteral("builtinExtensionNames"), engine->newFunction(UtilitiesExtension::js_builtinExtensionNames, 0)); + environmentObj.setProperty(QStringLiteral("isSharedLibrary"), + engine->newFunction(UtilitiesExtension::js_isSharedLibrary, 1)); + environmentObj.setProperty(QStringLiteral("getArchitecturesFromBinary"), + engine->newFunction(UtilitiesExtension::js_getArchitecturesFromBinary, 1)); extensionObject.setProperty(QStringLiteral("Utilities"), environmentObj); } diff --git a/src/lib/libs.qbs b/src/lib/libs.qbs index 478db3286..dd21cc081 100644 --- a/src/lib/libs.qbs +++ b/src/lib/libs.qbs @@ -3,7 +3,6 @@ import qbs Project { references: [ "corelib/corelib.qbs", - "qtprofilesetup/qtprofilesetup.qbs", "scriptengine/scriptengine.qbs", ] } diff --git a/src/lib/qtprofilesetup/qtenvironment.h b/src/lib/qtprofilesetup/qtenvironment.h deleted file mode 100644 index 72725cfae..000000000 --- a/src/lib/qtprofilesetup/qtenvironment.h +++ /dev/null @@ -1,101 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qbs. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** 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_QTENVIRONMENT_H -#define QBS_QTENVIRONMENT_H - -#include -#include - -#include - -namespace qbs { - -class QBS_EXPORT QtEnvironment { -public: - inline bool targetsDesktopWindows() const; - inline bool isForMinGw() const; - - QString installPrefixPath; - QString libraryPath; - QString includePath; - QString binaryPath; - QString qmlPath; - QString qmlImportPath; - QString documentationPath; - QString dataPath; - QString pluginPath; - QString qtLibInfix; - QString qtNameSpace; - QString mkspecPath; - QString mkspecName; - QString mkspecBasePath; - QStringList entryPointLibsDebug; - QStringList entryPointLibsRelease; - QStringList buildVariant; - QStringList configItems; - QStringList qtConfigItems; - QString architecture; - QString qtVersion; - QString windowsVersion; - QString macosVersion; - QString iosVersion; - QString tvosVersion; - QString watchosVersion; - QString androidVersion; - int qtMajorVersion; - int qtMinorVersion; - int qtPatchVersion; - bool staticBuild = false; - bool frameworkBuild = false; -}; - -bool QtEnvironment::targetsDesktopWindows() const -{ - return mkspecName.startsWith(QLatin1String("win32-")) || isForMinGw(); -} - -bool QtEnvironment::isForMinGw() const -{ - return mkspecName.startsWith(QLatin1String("win32-g++")) - || mkspecName.startsWith(QLatin1String("mingw")); -} - -} // namespace qbs - -#endif // Include guard. diff --git a/src/lib/qtprofilesetup/qtmoduleinfo.cpp b/src/lib/qtprofilesetup/qtmoduleinfo.cpp deleted file mode 100644 index bc3d25911..000000000 --- a/src/lib/qtprofilesetup/qtmoduleinfo.cpp +++ /dev/null @@ -1,839 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qbs. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** 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 "qtmoduleinfo.h" - -#include "qtenvironment.h" - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - -namespace qbs { -namespace Internal { - -typedef QHash NamePathHash; -static void replaceQtLibNamesWithFilePath(const NamePathHash &namePathHash, QStringList *libList) -{ - for (QString &lib : *libList) { - const NamePathHash::ConstIterator it = namePathHash.find(lib); - if (it != namePathHash.constEnd()) - lib = it.value(); - } -} - -static void replaceQtLibNamesWithFilePath(QList *modules, const QtEnvironment &qtEnv) -{ - // 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. - typedef QHash NamePathHash; - NamePathHash linkerNamesToFilePathsDebug; - NamePathHash linkerNamesToFilePathsRelease; - for (const QtModuleInfo &m : qAsConst(*modules)) { - linkerNamesToFilePathsDebug.insert(m.libNameForLinker(qtEnv, true), m.libFilePathDebug); - linkerNamesToFilePathsRelease.insert(m.libNameForLinker(qtEnv, false), - m.libFilePathRelease); - } - for (QtModuleInfo &module : *modules) { - replaceQtLibNamesWithFilePath(linkerNamesToFilePathsDebug, &module.dynamicLibrariesDebug); - replaceQtLibNamesWithFilePath(linkerNamesToFilePathsDebug, &module.staticLibrariesDebug); - replaceQtLibNamesWithFilePath(linkerNamesToFilePathsRelease, - &module.dynamicLibrariesRelease); - replaceQtLibNamesWithFilePath(linkerNamesToFilePathsRelease, - &module.staticLibrariesRelease); - } -} - -class DuplicatedDependencyLibsRemover -{ -public: - void apply(QList *modules) - { - setupReverseDependencies(modules); - - // Traverse the debug variants of modules. - m_getLibraries = [](QtModuleInfo *module) { - return std::vector{ - &module->dynamicLibrariesDebug, &module->staticLibrariesDebug - }; - }; - m_getLibFilePath = [](QtModuleInfo *module) { - return module->libFilePathDebug; - }; - const auto &rootModules = roots(modules); - for (QtModuleInfo *module : rootModules) - traverse(module, QStringList()); - - // Traverse the release variants of modules. - m_getLibraries = [](QtModuleInfo *module) { - return std::vector{ - &module->dynamicLibrariesRelease, &module->staticLibrariesRelease - }; - }; - m_getLibFilePath = [](QtModuleInfo *module) { - return module->libFilePathRelease; - }; - for (QtModuleInfo *module : rootModules) - traverse(module, QStringList()); - } - -private: - void setupReverseDependencies(QList *modules) - { - std::map moduleByName; - for (QtModuleInfo &module : *modules) - moduleByName[module.qbsName] = &module; - for (QtModuleInfo &module : *modules) { - for (const QString &dep : module.dependencies) { - QtModuleInfo *depmod = moduleByName[dep]; - if (!depmod) - continue; - m_revDeps[depmod].push_back(&module); - } - } - } - - std::vector roots(QList *modules) - { - std::vector result; - for (auto it = modules->begin(); it != modules->end(); ++it) { - QtModuleInfo &module = *it; - if (module.dependencies.empty()) - result.push_back(&module); - } - return result; - } - - void traverse(QtModuleInfo *module, QStringList libs) - { - if (contains(m_currentPath, module)) - return; - m_currentPath.push_back(module); - - auto isInLibs = [&libs](const QString &str) { - return std::binary_search(libs.begin(), libs.end(), str); - }; - auto moduleLibraryLists = m_getLibraries(module); - for (QStringList *lst : moduleLibraryLists) { - auto it = std::remove_if(lst->begin(), lst->end(), isInLibs); - if (it != lst->end()) - lst->erase(it, lst->end()); - } - const QString libFilePath = m_getLibFilePath(module); - if (!libFilePath.isEmpty()) - libs.push_back(libFilePath); - for (QStringList *lst : moduleLibraryLists) - std::copy(lst->begin(), lst->end(), std::back_inserter(libs)); - std::sort(libs.begin(), libs.end()); - - for (auto rdep : m_revDeps[module]) - traverse(rdep, libs); - - m_currentPath.pop_back(); - } - - std::unordered_map> m_revDeps; - std::vector m_currentPath; - std::function(QtModuleInfo *)> m_getLibraries; - std::function m_getLibFilePath; -}; - -static void removeDuplicatedDependencyLibs(QList *modules) -{ - DuplicatedDependencyLibsRemover dlr; - dlr.apply(modules); -} - -QtModuleInfo::QtModuleInfo() - : isPrivate(false), hasLibrary(true), isStaticLibrary(false), isPlugin(false), mustExist(true) -{ -} - -QtModuleInfo::QtModuleInfo(const QString &name, const QString &qbsName, const QStringList &deps) - : name(name), qbsName(qbsName), dependencies(deps), - isPrivate(qbsName.endsWith(QLatin1String("-private"))), - hasLibrary(!isPrivate), - isStaticLibrary(false), - isPlugin(false), - mustExist(true) -{ - const QString coreModule = QLatin1String("core"); - if (qbsName != coreModule && !dependencies.contains(coreModule)) - dependencies.prepend(coreModule); -} - -QString QtModuleInfo::moduleNameWithoutPrefix() const -{ - if (name == QLatin1String("Phonon")) - return QLatin1String("phonon"); - if (modulePrefix.isEmpty() && name.startsWith(QLatin1String("Qt"))) - return name.mid(2); // Strip off "Qt". - if (name.startsWith(modulePrefix)) - return name.mid(modulePrefix.length()); - return name; -} - -QString QtModuleInfo::frameworkHeadersPath(const QtEnvironment &qtEnvironment) const -{ - return qtEnvironment.libraryPath + QLatin1Char('/') + name - + QLatin1String(".framework/Headers"); -} - -QStringList QtModuleInfo::qt4ModuleIncludePaths(const QtEnvironment &qtEnvironment) const -{ - QStringList paths; - if (isFramework(qtEnvironment)) { - paths << frameworkHeadersPath(qtEnvironment); - } else { - paths << qtEnvironment.includePath - << qtEnvironment.includePath + QLatin1Char('/') + name; - } - return paths; -} - -QString QtModuleInfo::libraryBaseName(const QtEnvironment &qtEnvironment, - bool debugBuild) const -{ - if (isPlugin) - return libBaseName(name, debugBuild, qtEnvironment); - - // Some modules use a different naming scheme, so it doesn't get boring. - const bool libNameBroken = name == QLatin1String("Enginio") - || name == QLatin1String("DataVisualization") - || name == QLatin1String("Phonon"); - - QString libName = modulePrefix.isEmpty() && !libNameBroken ? QLatin1String("Qt") : modulePrefix; - if (qtEnvironment.qtMajorVersion >= 5 && !isFramework(qtEnvironment) && !libNameBroken) - libName += QString::number(qtEnvironment.qtMajorVersion); - libName += moduleNameWithoutPrefix(); - libName += qtEnvironment.qtLibInfix; - return libBaseName(libName, debugBuild, qtEnvironment); -} - -QString QtModuleInfo::libNameForLinker(const QtEnvironment &qtEnvironment, bool debugBuild) const -{ - if (!hasLibrary) - return QString(); - QString libName = libraryBaseName(qtEnvironment, debugBuild); - if (qtEnvironment.mkspecName.contains(QLatin1String("msvc"))) - libName += QLatin1String(".lib"); - return libName; -} - -void QtModuleInfo::setupLibraries(const QtEnvironment &qtEnv, - Internal::Set *nonExistingPrlFiles) -{ - setupLibraries(qtEnv, true, nonExistingPrlFiles); - setupLibraries(qtEnv, false, nonExistingPrlFiles); -} - -static QStringList makeList(const QByteArray &s) -{ - return QString::fromLatin1(s).split(QLatin1Char(' '), QString::SkipEmptyParts); -} - -static QString guessLibraryFilePath(const QString &prlFilePath, const QString &libDir, - const QtEnvironment &qtEnv) -{ - const QString baseName = QFileInfo(prlFilePath).baseName(); - const QStringList prefixCandidates{QString(), QLatin1String("lib")}; - const QStringList suffixCandidates{QLatin1String("so.") + qtEnv.qtVersion, - QLatin1String("so"), QLatin1String("a"), QLatin1String("lib"), - QLatin1String("dll.a")}; - for (const QString &prefix : prefixCandidates) { - for (const QString &suffix : suffixCandidates) { - const QString candidate = libDir + QLatin1Char('/') + prefix + baseName - + QLatin1Char('.') + suffix; - if (QFile::exists(candidate)) - return candidate; - } - } - return QString(); -} - -void QtModuleInfo::setupLibraries(const QtEnvironment &qtEnv, bool debugBuild, - Internal::Set *nonExistingPrlFiles) -{ - if (!hasLibrary) - return; // Can happen for Qt4 convenience modules, like "widgets". - - if (debugBuild) { - if (!qtEnv.buildVariant.contains(QLatin1String("debug"))) - return; - const QStringList modulesNeverBuiltAsDebug = QStringList() - << QLatin1String("bootstrap") << QLatin1String("qmldevtools"); - for (const QString &m : modulesNeverBuiltAsDebug) { - if (qbsName == m || qbsName == m + QLatin1String("-private")) - return; - } - } else if (!qtEnv.buildVariant.contains(QLatin1String("release"))) { - return; - } - - QStringList &libs = isStaticLibrary - ? (debugBuild ? staticLibrariesDebug : staticLibrariesRelease) - : (debugBuild ? dynamicLibrariesDebug : dynamicLibrariesRelease); - QStringList &frameworks = debugBuild ? frameworksDebug : frameworksRelease; - QStringList &frameworkPaths = debugBuild ? frameworkPathsDebug : frameworkPathsRelease; - QStringList &flags = debugBuild ? linkerFlagsDebug : linkerFlagsRelease; - QString &libFilePath = debugBuild ? libFilePathDebug : libFilePathRelease; - - if (qtEnv.mkspecName.contains(QLatin1String("ios")) && isStaticLibrary) { - libs << QLatin1String("z") << QLatin1String("m"); - if (qtEnv.qtMajorVersion == 5 && qtEnv.qtMinorVersion < 8) { - const QtModuleInfo platformSupportModule(QLatin1String("QtPlatformSupport"), - QLatin1String("platformsupport")); - libs << platformSupportModule.libNameForLinker(qtEnv, debugBuild); - } - if (name == QStringLiteral("qios")) { - flags << QLatin1String("-force_load") - << qtEnv.pluginPath + QLatin1String("/platforms/") - + libBaseName(QLatin1String("libqios"), debugBuild, qtEnv) - + QLatin1String(".a"); - } - } - - QString prlFilePath = isPlugin - ? qtEnv.pluginPath + QLatin1Char('/') + pluginData.type - : qtEnv.libraryPath; - prlFilePath += QLatin1Char('/'); - if (isFramework(qtEnv)) - prlFilePath.append(libraryBaseName(qtEnv, false)).append(QLatin1String(".framework/")); - const QString libDir = prlFilePath; - if (!qtEnv.mkspecName.startsWith(QLatin1String("win")) && !isFramework(qtEnv)) - prlFilePath += QLatin1String("lib"); - prlFilePath.append(libraryBaseName(qtEnv, debugBuild)); - const bool isNonStaticQt4OnWindows = qtEnv.mkspecName.startsWith(QLatin1String("win")) - && !isStaticLibrary && qtEnv.qtMajorVersion < 5; - if (isNonStaticQt4OnWindows) - prlFilePath.chop(1); // The prl file base name does *not* contain the version number... - prlFilePath.append(QLatin1String(".prl")); - QFile prlFile(prlFilePath); - if (!prlFile.open(QIODevice::ReadOnly)) { - libFilePath = guessLibraryFilePath(prlFilePath, libDir, qtEnv); - if (nonExistingPrlFiles->insert(prlFilePath).second) { - if (mustExist && libFilePath.isEmpty()) { - qDebug("Could not open prl file '%s' for module '%s' (%s), and failed to deduce " - "the library file path. This module will likely not be usable by qbs.", - qPrintable(prlFilePath), qPrintable(name), - qPrintable(prlFile.errorString())); - } - } - return; - } - const QList prlLines = prlFile.readAll().split('\n'); - for (const QByteArray &line : prlLines) { - const QByteArray simplifiedLine = line.simplified(); - const int equalsOffset = simplifiedLine.indexOf('='); - if (equalsOffset == -1) - continue; - if (simplifiedLine.startsWith("QMAKE_PRL_TARGET")) { - const bool isMingw = qtEnv.mkspecName.startsWith(QLatin1String("win")) - && qtEnv.mkspecName.contains(QLatin1String("g++")); - const bool isQtVersionBefore56 = qtEnv.qtMajorVersion < 5 - || (qtEnv.qtMajorVersion == 5 && qtEnv.qtMinorVersion < 6); - libFilePath = libDir; - - // QMAKE_PRL_TARGET has a "lib" prefix, except for mingw. - // Of course, the exception has an exception too: For static libs, mingw *does* - // have the "lib" prefix. TODO: Shoot the people responsible for this. - if (isQtVersionBefore56 && isMingw && !isStaticLibrary) - libFilePath += QLatin1String("lib"); - - libFilePath += QString::fromLatin1(simplifiedLine.mid(equalsOffset + 1).trimmed()); - if (isNonStaticQt4OnWindows) - libFilePath += QString::number(4); // This is *not* part of QMAKE_PRL_TARGET... - if (isQtVersionBefore56) { - if (qtEnv.mkspecName.contains(QLatin1String("msvc"))) - libFilePath += QLatin1String(".lib"); - else if (isMingw) - libFilePath += QLatin1String(".a"); - } - continue; - } - if (simplifiedLine.startsWith("QMAKE_PRL_CONFIG")) { - config = QString::fromLatin1(simplifiedLine.mid(equalsOffset + 1).trimmed()) - .split(QLatin1Char(' '), QString::SkipEmptyParts); - continue; - } - if (!simplifiedLine.startsWith("QMAKE_PRL_LIBS")) - continue; - - // Assuming lib names and directories without spaces here. - QStringList parts = QString::fromLatin1(simplifiedLine.mid(equalsOffset + 1).trimmed()) - .split(QLatin1Char(' '), QString::SkipEmptyParts); - for (int i = 0; i < parts.size(); ++i) { - QString part = parts.at(i); - part.replace(QLatin1String("$$[QT_INSTALL_LIBS]"), qtEnv.libraryPath); - if (part.startsWith(QLatin1String("-l"))) { - libs << part.mid(2); - } else if (part.startsWith(QLatin1String("-L"))) { - libraryPaths << part.mid(2); - } else if (part.startsWith(QLatin1String("-F"))) { - frameworkPaths << part.mid(2); - } else if (part == QLatin1String("-framework")) { - if (++i < parts.size()) - frameworks << parts.at(i); - } else if (part == QLatin1String("-pthread")) { - libs << QLatin1String("pthread"); - } else if (part.startsWith(QLatin1Char('-'))) { // Some other option - qDebug("QMAKE_PRL_LIBS contains non-library option '%s' in file '%s'", - qPrintable(part), qPrintable(prlFilePath)); - flags << part; - } else if (part.startsWith(QLatin1String("/LIBPATH:"))) { - libraryPaths << part.mid(9).replace(QLatin1String("\\\\"), QLatin1String("/")); - } else { // Assume it's a file path/name. - libs << part.replace(QLatin1String("\\\\"), QLatin1String("/")); - } - } - - return; - } -} - -bool QtModuleInfo::isFramework(const QtEnvironment &qtEnv) const -{ - if (!qtEnv.frameworkBuild || isStaticLibrary) - return false; - const QStringList modulesNeverBuiltAsFrameworks = QStringList() - << QLatin1String("bootstrap") << QLatin1String("openglextensions") - << QLatin1String("platformsupport") << QLatin1String("qmldevtools") - << QLatin1String("uitools") << QLatin1String("harfbuzzng"); - return !modulesNeverBuiltAsFrameworks.contains(qbsName); -} - -// We erroneously called the "testlib" module "test" for quite a while. Let's not punish users -// for that. -static void addTestModule(QList &modules) -{ - QtModuleInfo testModule(QLatin1String("QtTest"), QLatin1String("test"), - QStringList() << QLatin1String("testlib")); - testModule.hasLibrary = false; - modules.push_back(testModule); -} - -// See above. -static void addDesignerComponentsModule(QList &modules) -{ - QtModuleInfo module(QLatin1String("QtDesignerComponents"), - QLatin1String("designercomponents"), - QStringList() << QLatin1String("designercomponents-private")); - module.hasLibrary = false; - modules.push_back(module); -} - - -QList allQt4Modules(const QtEnvironment &qtEnvironment) -{ - // as per http://doc.qt.io/qt-4.8/modules.html + private stuff. - QList modules; - - QtModuleInfo core(QLatin1String("QtCore"), QLatin1String("core")); - core.compilerDefines << QLatin1String("QT_CORE_LIB"); - if (!qtEnvironment.qtNameSpace.isEmpty()) - core.compilerDefines << QLatin1String("QT_NAMESPACE=") + qtEnvironment.qtNameSpace; - - modules = QList() - << core - << QtModuleInfo(QLatin1String("QtCore"), QLatin1String("core-private"), - QStringList() << QLatin1String("core")) - << QtModuleInfo(QLatin1String("QtGui"), QLatin1String("gui")) - << QtModuleInfo(QLatin1String("QtGui"), QLatin1String("gui-private"), - QStringList() << QLatin1String("gui")) - << QtModuleInfo(QLatin1String("QtMultimedia"), QLatin1String("multimedia"), - QStringList() << QLatin1String("gui") << QLatin1String("network")) - << QtModuleInfo(QLatin1String("QtMultimedia"), QLatin1String("multimedia-private"), - QStringList() << QLatin1String("multimedia")) - << QtModuleInfo(QLatin1String("QtNetwork"), QLatin1String("network")) - << QtModuleInfo(QLatin1String("QtNetwork"), QLatin1String("network-private"), - QStringList() << QLatin1String("network")) - << QtModuleInfo(QLatin1String("QtOpenGL"), QLatin1String("opengl"), - QStringList() << QLatin1String("gui")) - << QtModuleInfo(QLatin1String("QtOpenGL"), QLatin1String("opengl-private"), - QStringList() << QLatin1String("opengl")) - << QtModuleInfo(QLatin1String("QtOpenVG"), QLatin1String("openvg"), - QStringList() << QLatin1String("gui")) - << QtModuleInfo(QLatin1String("QtScript"), QLatin1String("script")) - << QtModuleInfo(QLatin1String("QtScript"), QLatin1String("script-private"), - QStringList() << QLatin1String("script")) - << QtModuleInfo(QLatin1String("QtScriptTools"), QLatin1String("scripttools"), - QStringList() << QLatin1String("script") << QLatin1String("gui")) - << QtModuleInfo(QLatin1String("QtScriptTools"), QLatin1String("scripttools-private"), - QStringList() << QLatin1String("scripttools")) - << QtModuleInfo(QLatin1String("QtSql"), QLatin1String("sql")) - << QtModuleInfo(QLatin1String("QtSql"), QLatin1String("sql-private"), - QStringList() << QLatin1String("sql")) - << QtModuleInfo(QLatin1String("QtSvg"), QLatin1String("svg"), - QStringList() << QLatin1String("gui")) - << QtModuleInfo(QLatin1String("QtSvg"), QLatin1String("svg-private"), - QStringList() << QLatin1String("svg")) - << QtModuleInfo(QLatin1String("QtWebKit"), QLatin1String("webkit"), - QStringList() << QLatin1String("gui") << QLatin1String("network")) - << QtModuleInfo(QLatin1String("QtWebKit"), QLatin1String("webkit-private"), - QStringList() << QLatin1String("webkit")) - << QtModuleInfo(QLatin1String("QtXml"), QLatin1String("xml")) - << QtModuleInfo(QLatin1String("QtXml"), QLatin1String("xml-private"), - QStringList() << QLatin1String("xml")) - << QtModuleInfo(QLatin1String("QtXmlPatterns"), QLatin1String("xmlpatterns"), - QStringList() << QLatin1String("network")) - << QtModuleInfo(QLatin1String("QtXmlPatterns"), - QLatin1String("xmlpatterns-private"), - QStringList() << QLatin1String("xmlpatterns")) - << QtModuleInfo(QLatin1String("QtDeclarative"), QLatin1String("declarative"), - QStringList() << QLatin1String("gui") << QLatin1String("script")) - << QtModuleInfo(QLatin1String("QtDeclarative"), - QLatin1String("declarative-private"), - QStringList() << QLatin1String("declarative")) - << QtModuleInfo(QLatin1String("QtDesigner"), QLatin1String("designer"), - QStringList() << QLatin1String("gui") << QLatin1String("xml")) - << QtModuleInfo(QLatin1String("QtDesigner"), QLatin1String("designer-private"), - QStringList() << QLatin1String("designer")) - << QtModuleInfo(QLatin1String("QtUiTools"), QLatin1String("uitools")) - << QtModuleInfo(QLatin1String("QtUiTools"), QLatin1String("uitools-private"), - QStringList() << QLatin1String("uitools")) - << QtModuleInfo(QLatin1String("QtHelp"), QLatin1String("help"), - QStringList() << QLatin1String("network") << QLatin1String("sql")) - << QtModuleInfo(QLatin1String("QtHelp"), QLatin1String("help-private"), - QStringList() << QLatin1String("help")) - << QtModuleInfo(QLatin1String("QtTest"), QLatin1String("testlib")) - << QtModuleInfo(QLatin1String("QtTest"), QLatin1String("testlib-private"), - QStringList() << QLatin1String("testlib")); - - if (qtEnvironment.mkspecName.startsWith(QLatin1String("win"))) { - QtModuleInfo axcontainer(QLatin1String("QAxContainer"), QLatin1String("axcontainer")); - axcontainer.modulePrefix = QLatin1String("Q"); - axcontainer.isStaticLibrary = true; - axcontainer.includePaths << qtEnvironment.includePath + QLatin1String("/ActiveQt"); - modules.push_back(axcontainer); - - QtModuleInfo axserver = axcontainer; - axserver.name = QLatin1String("QAxServer"); - axserver.qbsName = QLatin1String("axserver"); - axserver.compilerDefines = QStringList() << QLatin1String("QAXSERVER"); - modules.push_back(axserver); - } else { - modules.push_back(QtModuleInfo(QLatin1String("QtDBus"), QLatin1String("dbus"))); - modules.push_back(QtModuleInfo(QLatin1String("QtDBus"), QLatin1String("dbus-private"), - { QLatin1String("dbus") })); - } - - QtModuleInfo designerComponentsPrivate(QLatin1String("QtDesignerComponents"), - QLatin1String("designercomponents-private"), - QStringList() << QLatin1String("gui-private") << QLatin1String("designer-private")); - designerComponentsPrivate.hasLibrary = true; - modules.push_back(designerComponentsPrivate); - - QtModuleInfo phonon(QLatin1String("Phonon"), QLatin1String("phonon")); - phonon.includePaths = phonon.qt4ModuleIncludePaths(qtEnvironment); - modules.push_back(phonon); - - // Set up include paths that haven't been set up before this point. - for (auto &module : modules) { - if (!module.includePaths.empty()) - continue; - module.includePaths = module.qt4ModuleIncludePaths(qtEnvironment); - } - - // Set up compiler defines haven't been set up before this point. - for (auto &module : modules) { - if (!module.compilerDefines.empty()) - continue; - module.compilerDefines - << QLatin1String("QT_") + module.qbsName.toUpper() + QLatin1String("_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. - QtModuleInfo virtualModule; - virtualModule.hasLibrary = false; - virtualModule.qbsName = QLatin1String("widgets"); - virtualModule.dependencies = QStringList() << QLatin1String("core") << QLatin1String("gui"); - modules.push_back(virtualModule); - virtualModule.qbsName = QLatin1String("quick"); - virtualModule.dependencies = QStringList() << QLatin1String("declarative"); - modules.push_back(virtualModule); - virtualModule.qbsName = QLatin1String("concurrent"); - virtualModule.dependencies = QStringList() << QLatin1String("core"); - modules.push_back(virtualModule); - virtualModule.qbsName = QLatin1String("printsupport"); - virtualModule.dependencies = QStringList() << QLatin1String("core") << QLatin1String("gui"); - modules.push_back(virtualModule); - - addTestModule(modules); - addDesignerComponentsModule(modules); - - const QStringList modulesThatCanBeDisabled = QStringList() << QLatin1String("xmlpatterns") - << QLatin1String("multimedia") << QLatin1String("phonon") << QLatin1String("svg") - << QLatin1String("webkit") << QLatin1String("script") << QLatin1String("scripttools") - << QLatin1String("declarative") << QLatin1String("gui") << QLatin1String("dbus") - << QLatin1String("opengl") << QLatin1String("openvg"); - for (auto &module : modules) { - QString name = module.qbsName; - name.remove(QLatin1String("-private")); - if (modulesThatCanBeDisabled.contains(name)) - module.mustExist = false; - } - - Internal::Set nonExistingPrlFiles; - for (QtModuleInfo &module : modules) { - if (qtEnvironment.staticBuild) - module.isStaticLibrary = true; - module.setupLibraries(qtEnvironment, &nonExistingPrlFiles); - } - replaceQtLibNamesWithFilePath(&modules, qtEnvironment); - - return modules; -} - -static QList getPriFileContentsRecursively(const Profile &profile, - const QString &priFilePath) -{ - QFile priFile(priFilePath); - if (!priFile.open(QIODevice::ReadOnly)) { - throw ErrorInfo(Tr::tr("Setting up Qt profile '%1' failed: Cannot open " - "file '%2' (%3).").arg(profile.name(), priFile.fileName(), priFile.errorString())); - } - QList lines = priFile.readAll().split('\n'); - for (int i = 0; i < lines.size(); ++i) { - const QByteArray includeString = "include("; - const QByteArray &line = lines.at(i).trimmed(); - if (!line.startsWith(includeString)) - continue; - const int offset = includeString.size(); - const int closingParenPos = line.indexOf(')', offset); - if (closingParenPos == -1) { - qDebug("Warning: Invalid include statement in '%s'", qPrintable(priFilePath)); - continue; - } - const QString includedFilePath - = QString::fromLocal8Bit(line.mid(offset, closingParenPos - offset)); - const QList &includedContents - = getPriFileContentsRecursively(profile, includedFilePath); - int j = i; - for (const QByteArray &includedLine : includedContents) - lines.insert(++j, includedLine); - lines.removeAt(i--); - } - return lines; -} - -static QStringList extractPaths(const QByteArray &rhs, const QString &filePath) -{ - QStringList paths; - int startIndex = 0; - for (;;) { - while (startIndex < rhs.size() && rhs.at(startIndex) == ' ') - ++startIndex; - if (startIndex >= rhs.size()) - break; - int endIndex; - if (rhs.at(startIndex) == '"') { - ++startIndex; - endIndex = rhs.indexOf('"', startIndex); - if (endIndex == -1) { - qDebug("Unmatched quote in file '%s'", qPrintable(filePath)); - break; - } - } else { - endIndex = rhs.indexOf(' ', startIndex + 1); - if (endIndex == -1) - endIndex = rhs.size(); - } - paths << QString::fromLocal8Bit(rhs.mid(startIndex, endIndex - startIndex)); - startIndex = endIndex + 1; - } - return paths; -} - -QList allQt5Modules(const Profile &profile, const QtEnvironment &qtEnvironment) -{ - Internal::Set nonExistingPrlFiles; - QList modules; - QDirIterator dit(qtEnvironment.mkspecBasePath + QLatin1String("/modules")); - while (dit.hasNext()) { - const QString moduleFileNamePrefix = QLatin1String("qt_lib_"); - const QString pluginFileNamePrefix = QLatin1String("qt_plugin_"); - const QString moduleFileNameSuffix = QLatin1String(".pri"); - dit.next(); - const bool fileHasPluginPrefix = dit.fileName().startsWith(pluginFileNamePrefix); - if ((!fileHasPluginPrefix && !dit.fileName().startsWith(moduleFileNamePrefix)) - || !dit.fileName().endsWith(moduleFileNameSuffix)) { - continue; - } - QtModuleInfo moduleInfo; - moduleInfo.isPlugin = fileHasPluginPrefix; - const QString fileNamePrefix - = moduleInfo.isPlugin ? pluginFileNamePrefix : moduleFileNamePrefix; - moduleInfo.qbsName = dit.fileName().mid(fileNamePrefix.size(), - dit.fileName().size() - fileNamePrefix.size() - - moduleFileNameSuffix.size()); - if (moduleInfo.isPlugin) { - moduleInfo.name = moduleInfo.qbsName; - moduleInfo.isStaticLibrary = true; - } - const QByteArray moduleKeyPrefix = QByteArray(moduleInfo.isPlugin ? "QT_PLUGIN" : "QT") - + '.' + moduleInfo.qbsName.toLatin1() + '.'; - moduleInfo.qbsName.replace(QLatin1String("_private"), QLatin1String("-private")); - bool hasV2 = false; - bool hasModuleEntry = false; - const auto lines = getPriFileContentsRecursively(profile, dit.filePath()); - for (const QByteArray &line : lines) { - const QByteArray simplifiedLine = line.simplified(); - const int firstEqualsOffset = simplifiedLine.indexOf('='); - if (firstEqualsOffset == -1) - continue; - const QByteArray key = simplifiedLine.left(firstEqualsOffset).trimmed(); - const QByteArray value = simplifiedLine.mid(firstEqualsOffset + 1).trimmed(); - if (!key.startsWith(moduleKeyPrefix) || value.isEmpty()) - continue; - if (key.endsWith(".name")) { - moduleInfo.name = QString::fromLocal8Bit(value); - } else if (key.endsWith(".module")) { - hasModuleEntry = true; - } else if (key.endsWith(".depends")) { - moduleInfo.dependencies = QString::fromLocal8Bit(value).split(QLatin1Char(' ')); - for (auto &dependency : moduleInfo.dependencies) - dependency.replace(QLatin1String("_private"), QLatin1String("-private")); - } else if (key.endsWith(".module_config")) { - const auto elems = value.split(' '); - for (const QByteArray &elem : elems) { - 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 (key.endsWith(".includes")) { - moduleInfo.includePaths = extractPaths(value, dit.filePath()); - for (auto &includePath : moduleInfo.includePaths) { - includePath - .replace(QLatin1String("$$QT_MODULE_INCLUDE_BASE"), - qtEnvironment.includePath) - .replace(QLatin1String("$$QT_MODULE_LIB_BASE"), - qtEnvironment.libraryPath); - } - } else if (key.endsWith(".DEFINES")) { - moduleInfo.compilerDefines = QString::fromLocal8Bit(value) - .split(QLatin1Char(' '), QString::SkipEmptyParts); - } else if (key.endsWith(".VERSION")) { - moduleInfo.version = QString::fromLocal8Bit(value); - } else if (key.endsWith(".plugin_types")) { - moduleInfo.supportedPluginTypes = makeList(value); - } else if (key.endsWith(".TYPE")) { - moduleInfo.pluginData.type = QString::fromLatin1(value); - } else if (key.endsWith(".EXTENDS")) { - moduleInfo.pluginData.extends = makeList(value); - if (moduleInfo.pluginData.extends.removeOne(QLatin1String("-"))) - moduleInfo.pluginData.autoLoad = false; - } else if (key.endsWith(".CLASS_NAME")) { - moduleInfo.pluginData.className = QString::fromLatin1(value); - } - } - if (hasV2 && !hasModuleEntry) - moduleInfo.hasLibrary = false; - - // Fix include paths for Apple frameworks. - // The qt_lib_XXX.pri files contain wrong values for versions < 5.6. - if (!hasV2 && moduleInfo.isFramework(qtEnvironment)) { - moduleInfo.includePaths.clear(); - QString baseIncDir = moduleInfo.frameworkHeadersPath(qtEnvironment); - if (moduleInfo.isPrivate) { - baseIncDir += QLatin1Char('/') + moduleInfo.version; - moduleInfo.includePaths - << baseIncDir - << baseIncDir + QLatin1Char('/') + moduleInfo.name; - } else { - moduleInfo.includePaths << baseIncDir; - } - } - - moduleInfo.setupLibraries(qtEnvironment, &nonExistingPrlFiles); - - modules.push_back(moduleInfo); - if (moduleInfo.qbsName == QLatin1String("testlib")) - addTestModule(modules); - if (moduleInfo.qbsName == QLatin1String("designercomponents-private")) - addDesignerComponentsModule(modules); - } - - replaceQtLibNamesWithFilePath(&modules, qtEnvironment); - removeDuplicatedDependencyLibs(&modules); - return modules; -} - -QString QtModuleInfo::libBaseName(const QString &libName, bool debugBuild, - const QtEnvironment &qtEnvironment) const -{ - QString name = libName; - if (qtEnvironment.mkspecName.startsWith(QLatin1String("win"))) { - if (debugBuild) - name += QLatin1Char('d'); - if (!isStaticLibrary && qtEnvironment.qtMajorVersion < 5) - name += QString::number(qtEnvironment.qtMajorVersion); - } - if (qtEnvironment.mkspecName.contains(QLatin1String("macx")) - || qtEnvironment.mkspecName.contains(QLatin1String("ios")) - || qtEnvironment.mkspecName.contains(QLatin1String("darwin"))) { - if (!isFramework(qtEnvironment) - && qtEnvironment.buildVariant.contains(QLatin1String("debug")) - && (!qtEnvironment.buildVariant.contains(QLatin1String("release")) || debugBuild)) { - name += QLatin1String("_debug"); - } - } - return name; -} - -} // namespace Internal -} // namespace qbs - diff --git a/src/lib/qtprofilesetup/qtmoduleinfo.h b/src/lib/qtprofilesetup/qtmoduleinfo.h deleted file mode 100644 index 38a654edf..000000000 --- a/src/lib/qtprofilesetup/qtmoduleinfo.h +++ /dev/null @@ -1,115 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qbs. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** 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_QTMODULEINFO_H -#define QBS_QTMODULEINFO_H - -#include - -namespace qbs { -class QtEnvironment; -class Profile; - -namespace Internal { - -template class Set; - -class QtModuleInfo -{ -public: - QtModuleInfo(); - QtModuleInfo(const QString &name, const QString &qbsName, - const QStringList &deps = QStringList()); - - QString moduleNameWithoutPrefix() const; - QString frameworkHeadersPath(const QtEnvironment &qtEnvironment) const; - QStringList qt4ModuleIncludePaths(const QtEnvironment &qtEnvironment) const; - QString libraryBaseName(const QtEnvironment &qtEnvironment, bool debugBuild) const; - QString libBaseName(const QString &libName, bool debugBuild, - const QtEnvironment &qtEnvironment) const; - QString libNameForLinker(const QtEnvironment &qtEnvironment, bool debugBuild) const; - void setupLibraries(const QtEnvironment &qtEnv, Internal::Set *nonExistingPrlFiles); - bool isFramework(const QtEnvironment &qtEnv) const; - - QString modulePrefix; // default is empty and means "Qt". - QString name; // As in the path to the headers and ".name" in the pri files. - QString qbsName; // Lower-case version without "qt" prefix. - QString version; - QStringList dependencies; // qbs names. - QStringList includePaths; - QStringList compilerDefines; - QStringList staticLibrariesDebug; - QStringList staticLibrariesRelease; - QStringList dynamicLibrariesDebug; - QStringList dynamicLibrariesRelease; - QStringList linkerFlagsDebug; - QStringList linkerFlagsRelease; - QString libFilePathDebug; - QString libFilePathRelease; - QStringList frameworksDebug; - QStringList frameworksRelease; - QStringList frameworkPathsDebug; - QStringList frameworkPathsRelease; - QStringList libraryPaths; - QStringList config; - bool isPrivate; - bool hasLibrary; - bool isStaticLibrary; - bool isPlugin; - bool mustExist; - QStringList supportedPluginTypes; - - struct PluginData { - QString type; - QStringList extends; - QString className; - bool autoLoad = true; - } pluginData; - -private: - void setupLibraries(const QtEnvironment &qtEnv, bool debugBuild, - Internal::Set *nonExistingPrlFiles); -}; - -QList allQt4Modules(const QtEnvironment &qtEnvironment); -QList allQt5Modules(const Profile &profile, const QtEnvironment &qtEnvironment); - -} // namespace Internal -} // namespace qbs - -#endif // Include guard. diff --git a/src/lib/qtprofilesetup/qtmsvctools.cpp b/src/lib/qtprofilesetup/qtmsvctools.cpp deleted file mode 100644 index 0c41b928c..000000000 --- a/src/lib/qtprofilesetup/qtmsvctools.cpp +++ /dev/null @@ -1,79 +0,0 @@ -/**************************************************************************** -** -** 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 "qtmsvctools.h" - -namespace qbs { - -static const QString msvcPrefix = QLatin1String("win32-msvc"); - -bool isMsvcQt(const QtEnvironment &env) -{ - return env.mkspecName.startsWith(msvcPrefix); -} - -static Version msvcCompilerVersionForYear(int year) -{ - switch (year) - { - case 2005: - return Version(14); - case 2008: - return Version(15); - case 2010: - return Version(16); - case 2012: - return Version(17); - case 2013: - return Version(18); - case 2015: - return Version(19); - case 2017: - return Version(19, 1); - default: - return Version(); - } -} - -Version msvcCompilerVersionFromMkspecName(const QString &mkspecName) -{ - return msvcCompilerVersionForYear(mkspecName.mid(msvcPrefix.size()).toInt()); -} - -} // namespace qbs diff --git a/src/lib/qtprofilesetup/qtmsvctools.h b/src/lib/qtprofilesetup/qtmsvctools.h deleted file mode 100644 index 195d0e0ec..000000000 --- a/src/lib/qtprofilesetup/qtmsvctools.h +++ /dev/null @@ -1,49 +0,0 @@ -/**************************************************************************** -** -** 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 "qtenvironment.h" -#include -#include - -namespace qbs { - -QBS_EXPORT bool isMsvcQt(const QtEnvironment &env); -QBS_EXPORT Version msvcCompilerVersionFromMkspecName(const QString &mkspecName); - -} // namespace qbs diff --git a/src/lib/qtprofilesetup/qtprofilesetup.cpp b/src/lib/qtprofilesetup/qtprofilesetup.cpp deleted file mode 100644 index 7fabcb5c9..000000000 --- a/src/lib/qtprofilesetup/qtprofilesetup.cpp +++ /dev/null @@ -1,930 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qbs. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** 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 "qtprofilesetup.h" - -#include "qtmoduleinfo.h" -#include "qtmsvctools.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#ifdef __APPLE__ -#include -#include -#include -#include -#if __MAC_OS_X_VERSION_MAX_ALLOWED < 101200 -#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 - -namespace qbs { -using namespace Internal; - -template -QByteArray utf8JSLiteral(T t) -{ - return toJSLiteral(t).toUtf8(); -} - -static QString pathToJSLiteral(const QString &path) -{ - return toJSLiteral(QDir::fromNativeSeparators(path)); -} - -static QString defaultQpaPlugin(const Profile &profile, const QtModuleInfo &module, - const QtEnvironment &qtEnv) -{ - if (qtEnv.qtMajorVersion < 5) - return QString(); - - if (qtEnv.qtMajorVersion == 5 && qtEnv.qtMinorVersion < 8) { - QFile qConfigPri(qtEnv.mkspecBasePath + QLatin1String("/qconfig.pri")); - if (!qConfigPri.open(QIODevice::ReadOnly)) { - throw ErrorInfo(Tr::tr("Setting up Qt profile '%1' failed: Cannot open " - "file '%2' (%3).") - .arg(profile.name(), qConfigPri.fileName(), qConfigPri.errorString())); - } - const QList lines = qConfigPri.readAll().split('\n'); - const QByteArray magicString = "QT_DEFAULT_QPA_PLUGIN ="; - for (const QByteArray &line : lines) { - const QByteArray simplifiedLine = line.simplified(); - if (simplifiedLine.startsWith(magicString)) - return QString::fromLatin1(simplifiedLine.mid(magicString.size()).trimmed()); - } - } else { - const QString qtGuiConfigHeader = (qtEnv.frameworkBuild - ? qtEnv.libraryPath - : qtEnv.includePath) - + QStringLiteral("/QtGui") - + (qtEnv.frameworkBuild ? QStringLiteral(".framework/Headers") : QString()) - + QStringLiteral("/qtgui-config.h"); - std::queue headerFiles; - headerFiles.push(qtGuiConfigHeader); - while (!headerFiles.empty()) { - QFile headerFile(headerFiles.front()); - headerFiles.pop(); - if (!headerFile.open(QIODevice::ReadOnly)) { - throw ErrorInfo(Tr::tr("Setting up Qt profile '%1' failed: Cannot open " - "file '%2' (%3).") - .arg(profile.name(), headerFile.fileName(), - headerFile.errorString())); - } - static const std::regex regexp( - "^#define QT_QPA_DEFAULT_PLATFORM_NAME \"(.+)\".*$"); - static const std::regex includeRegexp( - "^#include \"(.+)\".*$"); - const QList lines = headerFile.readAll().split('\n'); - for (const QByteArray &line: lines) { - const auto lineStr = QString::fromLatin1(line.simplified()).toStdString(); - std::smatch match; - if (std::regex_match(lineStr, match, regexp)) - return QLatin1Char('q') + QString::fromStdString(match[1]); - if (std::regex_match(lineStr, match, includeRegexp)) { - QString filePath = QString::fromStdString(match[1]); - if (QFileInfo(filePath).isRelative()) { - filePath = QDir::cleanPath(QFileInfo(headerFile.fileName()).absolutePath() - + QLatin1Char('/') + filePath); - } - headerFiles.push(filePath); - } - } - } - } - - if (module.isStaticLibrary) - qDebug("Warning: Could not determine default QPA plugin for static Qt."); - return QString(); -} - -static QByteArray minVersionJsString(const QString &minVersion) -{ - if (minVersion.isEmpty()) - return "original"; - return utf8JSLiteral(minVersion); -} - -#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 QString(); - } - 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 QString(); - } - 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 QString(); - } - case CPU_TYPE_ARM64: - switch (cpusubtype) { - case CPU_SUBTYPE_ARM64_ALL: - return QStringLiteral("arm64"); - default: - return QString(); - } - default: - return QString(); - } -} - -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 QStringList(); - - 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(); - - 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 QStringList(); - - 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 QStringList(); - } - 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 QStringList(); - - 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 QStringList(); - } - - header.cputype = static_cast(readInt(device, &ok, swap)); - if (!ok) - return QStringList(); - - header.cpusubtype = static_cast(readInt(device, &ok, swap)); - if (!ok) - return QStringList(); - - 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 - -static QStringList extractQbsArchs(const QtModuleInfo &module, const QtEnvironment &qtEnv) -{ -#ifdef __APPLE__ - if (qtEnv.mkspecName.startsWith(QLatin1String("macx-"))) { - QStringList archs; - if (!module.libFilePathRelease.isEmpty()) { - QFile file(module.libFilePathRelease); - if (file.open(QIODevice::ReadOnly)) - archs = detectMachOArchs(&file); - else - qWarning("Failed to open %s for reading", - qUtf8Printable(module.libFilePathRelease)); - if (archs.isEmpty()) - qWarning("Could not detect architectures for module %s in Qt build (%s)", - qPrintable(module.name), qUtf8Printable(qtEnv.mkspecName)); - } - return archs; - } -#else - Q_UNUSED(module); -#endif - QString qbsArch = canonicalArchitecture(qtEnv.architecture); - if (qbsArch == QLatin1String("arm") && qtEnv.mkspecPath.contains(QLatin1String("android"))) - qbsArch = QLatin1String("armv7a"); - - // Qt4 has "QT_ARCH = windows" in qconfig.pri for both MSVC and mingw. - if (qbsArch == QLatin1String("windows")) - return QStringList(); - - return QStringList { qbsArch }; -} - -static std::pair findVariable(const QByteArray &content, int start) -{ - std::pair result = std::make_pair(-1, -1); - result.first = content.indexOf('@', start); - if (result.first == -1) - return result; - result.second = content.indexOf('@', result.first + 1); - if (result.second == -1) { - result.first = -1; - return result; - } - for (char forbidden : {' ', '\n'}) { - int k = content.indexOf(forbidden, result.first + 1); - if (k != -1 && k < result.second) { - return findVariable(content, result.first + 1); - } - } - return result; -} - -static QByteArray libraryFileTag(const QtEnvironment &env, const QtModuleInfo &module) -{ - QByteArray result; - if (module.isStaticLibrary) { - result = "staticlibrary"; - } else { - result = isMsvcQt(env) || env.mkspecName.startsWith(QLatin1String("win32-g++")) - ? "dynamiclibrary_import" : "dynamiclibrary"; - } - return result; -} - -static void replaceSpecialValues(QByteArray *content, const Profile &profile, - const QtModuleInfo &module, const QtEnvironment &qtEnvironment) -{ - QHash dict; - dict.insert("archs", utf8JSLiteral(extractQbsArchs(module, qtEnvironment))); - dict.insert("targetPlatform", utf8JSLiteral(qbsTargetPlatformFromQtMkspec(qtEnvironment))); - dict.insert("config", utf8JSLiteral(qtEnvironment.configItems)); - dict.insert("qtConfig", utf8JSLiteral(qtEnvironment.qtConfigItems)); - dict.insert("binPath", utf8JSLiteral(qtEnvironment.binaryPath)); - dict.insert("libPath", utf8JSLiteral(qtEnvironment.libraryPath)); - dict.insert("pluginPath", utf8JSLiteral(qtEnvironment.pluginPath)); - dict.insert("incPath", utf8JSLiteral(qtEnvironment.includePath)); - dict.insert("docPath", utf8JSLiteral(qtEnvironment.documentationPath)); - dict.insert("mkspecName", utf8JSLiteral(qtEnvironment.mkspecName)); - dict.insert("mkspecPath", utf8JSLiteral(qtEnvironment.mkspecPath)); - dict.insert("version", utf8JSLiteral(qtEnvironment.qtVersion)); - dict.insert("libInfix", utf8JSLiteral(qtEnvironment.qtLibInfix)); - dict.insert("availableBuildVariants", utf8JSLiteral(qtEnvironment.buildVariant)); - dict.insert("staticBuild", utf8JSLiteral(qtEnvironment.staticBuild)); - dict.insert("frameworkBuild", utf8JSLiteral(qtEnvironment.frameworkBuild)); - dict.insert("name", utf8JSLiteral(module.moduleNameWithoutPrefix())); - dict.insert("has_library", utf8JSLiteral(module.hasLibrary)); - dict.insert("dependencies", utf8JSLiteral(module.dependencies)); - dict.insert("includes", utf8JSLiteral(module.includePaths)); - dict.insert("staticLibsDebug", utf8JSLiteral(module.staticLibrariesDebug)); - dict.insert("staticLibsRelease", utf8JSLiteral(module.staticLibrariesRelease)); - dict.insert("dynamicLibsDebug", utf8JSLiteral(module.dynamicLibrariesDebug)); - dict.insert("dynamicLibsRelease", utf8JSLiteral(module.dynamicLibrariesRelease)); - dict.insert("linkerFlagsDebug", utf8JSLiteral(module.linkerFlagsDebug)); - dict.insert("linkerFlagsRelease", utf8JSLiteral(module.linkerFlagsRelease)); - dict.insert("libraryPaths", utf8JSLiteral(module.libraryPaths)); - dict.insert("frameworkPathsDebug", utf8JSLiteral(module.frameworkPathsDebug)); - dict.insert("frameworkPathsRelease", utf8JSLiteral(module.frameworkPathsRelease)); - dict.insert("frameworksDebug", utf8JSLiteral(module.frameworksDebug)); - dict.insert("frameworksRelease", utf8JSLiteral(module.frameworksRelease)); - dict.insert("libFilePathDebug", utf8JSLiteral(module.libFilePathDebug)); - dict.insert("libFilePathRelease", utf8JSLiteral(module.libFilePathRelease)); - dict.insert("libNameForLinkerDebug", - utf8JSLiteral(module.libNameForLinker(qtEnvironment, true))); - dict.insert("pluginTypes", utf8JSLiteral(module.supportedPluginTypes)); - dict.insert("moduleConfig", utf8JSLiteral(module.config)); - dict.insert("libNameForLinkerRelease", - utf8JSLiteral(module.libNameForLinker(qtEnvironment, false))); - dict.insert("entryPointLibsDebug", utf8JSLiteral(qtEnvironment.entryPointLibsDebug)); - dict.insert("entryPointLibsRelease", utf8JSLiteral(qtEnvironment.entryPointLibsRelease)); - dict.insert("minWinVersion", minVersionJsString(qtEnvironment.windowsVersion)); - dict.insert("minMacVersion", minVersionJsString(qtEnvironment.macosVersion)); - dict.insert("minIosVersion", minVersionJsString(qtEnvironment.iosVersion)); - dict.insert("minTvosVersion", minVersionJsString(qtEnvironment.tvosVersion)); - dict.insert("minWatchosVersion", minVersionJsString(qtEnvironment.watchosVersion)); - dict.insert("minAndroidVersion", minVersionJsString(qtEnvironment.androidVersion)); - - QByteArray additionalContent; - QByteArray compilerDefines = utf8JSLiteral(module.compilerDefines); - if (module.qbsName == QLatin1String("declarative") - || module.qbsName == QLatin1String("quick")) { - const QByteArray debugMacro = module.qbsName == QLatin1String("declarative") - || qtEnvironment.qtMajorVersion < 5 - ? "QT_DECLARATIVE_DEBUG" : "QT_QML_DEBUG"; - - const QString indent = QLatin1String(" "); - QTextStream s(&additionalContent); - s << "property bool qmlDebugging: false" << endl; - s << indent << "property string qmlPath"; - if (qtEnvironment.qmlPath.isEmpty()) - s << endl; - else - s << ": " << pathToJSLiteral(qtEnvironment.qmlPath) << endl; - - s << indent << "property string qmlImportsPath: " - << pathToJSLiteral(qtEnvironment.qmlImportPath); - - const QByteArray baIndent(4, ' '); - compilerDefines = "{\n" - + baIndent + baIndent + "var result = " + compilerDefines + ";\n" - + baIndent + baIndent + "if (qmlDebugging)\n" - + baIndent + baIndent + baIndent + "result.push(\"" + debugMacro + "\");\n" - + baIndent + baIndent + "return result;\n" - + baIndent + "}"; - } - dict.insert("defines", compilerDefines); - if (module.qbsName == QLatin1String("gui")) { - dict.insert("defaultQpaPlugin", - utf8JSLiteral(defaultQpaPlugin(profile, module, qtEnvironment))); - } - if (module.qbsName == QLatin1String("qml")) - dict.insert("qmlPath", pathToJSLiteral(qtEnvironment.qmlPath).toUtf8()); - if (module.isStaticLibrary && module.qbsName != QLatin1String("core")) { - if (!additionalContent.isEmpty()) - additionalContent += "\n "; - additionalContent += "isStaticLibrary: true"; - } - if (module.isPlugin) { - dict.insert("className", utf8JSLiteral(module.pluginData.className)); - dict.insert("extends", utf8JSLiteral(module.pluginData.extends)); - } - if (module.hasLibrary && !module.isFramework(qtEnvironment)) { - if (!additionalContent.isEmpty()) - additionalContent += "\n"; - const QByteArray indent(4, ' '); - additionalContent += "Group {\n"; - if (module.isPlugin) { - additionalContent += indent + indent - + "condition: Qt[\"" + module.qbsName.toUtf8() + "\"].enableLinking\n"; - } - additionalContent += indent + indent + "files: [Qt[\"" + module.qbsName.toUtf8() + "\"]" - + ".libFilePath]\n" - + indent + indent + "filesAreTargets: true\n" - + indent + indent + "fileTags: [\"" + libraryFileTag(qtEnvironment, module) - + "\"]\n" - + indent + "}"; - } - dict.insert("additionalContent", additionalContent); - - for (std::pair pos = findVariable(*content, 0); pos.first != -1; - pos = findVariable(*content, pos.first)) { - const QByteArray &replacement = dict.value( - content->mid(pos.first + 1, pos.second - pos.first - 1)); - content->replace(pos.first, pos.second - pos.first + 1, replacement); - pos.first += replacement.length(); - } -} - -static void copyTemplateFile(const QString &fileName, const QString &targetDirectory, - const Profile &profile, const QtEnvironment &qtEnv, QStringList *allFiles, - const QtModuleInfo *module = nullptr, const QVariantMap &pluginMap = QVariantMap(), - const QStringList &nonEssentialPlugins = QStringList()) -{ - if (!QDir::root().mkpath(targetDirectory)) { - throw ErrorInfo(Internal::Tr::tr("Setting up Qt profile '%1' failed: " - "Cannot create directory '%2'.") - .arg(profile.name(), targetDirectory)); - } - QFile sourceFile(QLatin1String(":/templates/") + fileName); - if (!sourceFile.open(QIODevice::ReadOnly)) { - throw ErrorInfo(Internal::Tr::tr("Setting up Qt profile '%1' failed: " - "Cannot open '%1' (%2).").arg(sourceFile.fileName(), sourceFile.errorString())); - } - QByteArray newContent = sourceFile.readAll(); - if (module) { - replaceSpecialValues(&newContent, profile, *module, qtEnv); - } else { - newContent.replace("@allPluginsByType@", '(' + utf8JSLiteral(pluginMap) + ')'); - newContent.replace("@nonEssentialPlugins@", utf8JSLiteral(nonEssentialPlugins)); - } - sourceFile.close(); - const QString targetPath = targetDirectory + QLatin1Char('/') + fileName; - allFiles->push_back(QFileInfo(targetPath).absoluteFilePath()); - QFile targetFile(targetPath); - if (targetFile.open(QIODevice::ReadOnly)) { - if (newContent == targetFile.readAll()) // No need to overwrite anything in this case. - return; - targetFile.close(); - } - if (!targetFile.open(QIODevice::WriteOnly)) { - throw ErrorInfo(Internal::Tr::tr("Setting up Qt profile '%1' failed: " - "Cannot open '%1' (%2).").arg(targetFile.fileName(), targetFile.errorString())); - } - targetFile.resize(0); - targetFile.write(newContent); -} - -static void createModules(Profile &profile, Settings *settings, - const QtEnvironment &qtEnvironment) -{ - const QList modules = qtEnvironment.qtMajorVersion < 5 - ? allQt4Modules(qtEnvironment) - : allQt5Modules(profile, qtEnvironment); - QVariantMap pluginsByType; - QStringList nonEssentialPlugins; - for (const QtModuleInfo &m : modules) { - if (m.isPlugin) { - QVariant &v = pluginsByType[m.pluginData.type]; - v = v.toStringList() << m.name; - if (!m.pluginData.autoLoad) - nonEssentialPlugins << m.name; - } - } - const QString profileBaseDir = QString::fromLatin1("%1/profiles/%2") - .arg(QFileInfo(settings->fileName()).dir().absolutePath(), - profile.name()); - const QString qbsQtModuleBaseDir = profileBaseDir + QLatin1String("/modules/Qt"); - QStringList allFiles; - copyTemplateFile(QLatin1String("QtModule.qbs"), qbsQtModuleBaseDir, profile, qtEnvironment, - &allFiles); - copyTemplateFile(QLatin1String("QtPlugin.qbs"), qbsQtModuleBaseDir, profile, qtEnvironment, - &allFiles); - copyTemplateFile(QLatin1String("plugin_support.qbs"), - qbsQtModuleBaseDir + QLatin1String("/plugin_support"), profile, qtEnvironment, - &allFiles, nullptr, pluginsByType, nonEssentialPlugins); - for (const QtModuleInfo &module : modules) { - const QString qbsQtModuleDir = qbsQtModuleBaseDir + QLatin1Char('/') + module.qbsName; - QString moduleTemplateFileName; - if (module.qbsName == QLatin1String("core")) { - moduleTemplateFileName = QLatin1String("core.qbs"); - copyTemplateFile(QLatin1String("moc.js"), qbsQtModuleDir, profile, qtEnvironment, - &allFiles); - copyTemplateFile(QLatin1String("qdoc.js"), qbsQtModuleDir, profile, qtEnvironment, - &allFiles); - } else if (module.qbsName == QLatin1String("gui")) { - moduleTemplateFileName = QLatin1String("gui.qbs"); - } else if (module.qbsName == QLatin1String("scxml")) { - moduleTemplateFileName = QLatin1String("scxml.qbs"); - } else if (module.qbsName == QLatin1String("dbus")) { - moduleTemplateFileName = QLatin1String("dbus.qbs"); - copyTemplateFile(QLatin1String("dbus.js"), qbsQtModuleDir, profile, qtEnvironment, - &allFiles); - } else if (module.qbsName == QLatin1String("qml")) { - moduleTemplateFileName = QLatin1String("qml.qbs"); - copyTemplateFile(QLatin1String("qml.js"), qbsQtModuleDir, profile, qtEnvironment, - &allFiles); - const QString qmlcacheStr = QStringLiteral("qmlcache"); - if (QFileInfo::exists(HostOsInfo::appendExecutableSuffix( - qtEnvironment.binaryPath + QStringLiteral("/qmlcachegen")))) { - copyTemplateFile(qmlcacheStr + QStringLiteral(".qbs"), - qbsQtModuleBaseDir + QLatin1Char('/') + qmlcacheStr, profile, - qtEnvironment, &allFiles); - } - } else if (module.qbsName == QLatin1String("quick")) { - moduleTemplateFileName = QLatin1String("quick.qbs"); - copyTemplateFile(QLatin1String("quick.js"), qbsQtModuleDir, profile, - qtEnvironment, &allFiles); - } else if (module.isPlugin) { - moduleTemplateFileName = QLatin1String("plugin.qbs"); - } else { - moduleTemplateFileName = QLatin1String("module.qbs"); - } - copyTemplateFile(moduleTemplateFileName, qbsQtModuleDir, profile, qtEnvironment, &allFiles, - &module); - } - - // Note that it's not strictly necessary to copy this one, as it has no variable content. - // But we do it anyway for consistency (and it has no impact on the project files this way). - copyTemplateFile(QLatin1String("android_support.qbs"), - qbsQtModuleBaseDir + QLatin1String("/android_support"), profile, qtEnvironment, - &allFiles); - - QDirIterator dit(qbsQtModuleBaseDir, QDirIterator::Subdirectories); - while (dit.hasNext()) { - dit.next(); - const QFileInfo &fi = dit.fileInfo(); - if (!fi.isFile()) - continue; - const QString filePath = fi.absoluteFilePath(); - if (!allFiles.contains(filePath) && !QFile::remove(filePath)) - qDebug("Warning: Failed to remove outdated file '%s'.", qPrintable(filePath)); - } - profile.setValue(QLatin1String("preferences.qbsSearchPaths"), profileBaseDir); -} - -static QString guessMinimumWindowsVersion(const QtEnvironment &qt) -{ - if (qt.mkspecName.startsWith(QLatin1String("winrt-"))) - return QLatin1String("10.0"); - - if (!qt.targetsDesktopWindows()) - return QString(); - - if (qt.architecture == QLatin1String("x86_64") - || qt.architecture == QLatin1String("ia64")) { - return QLatin1String("5.2"); - } - - QRegExp rex(QLatin1String("^win32-msvc(\\d+)$")); - if (rex.exactMatch(qt.mkspecName)) { - int msvcVersion = rex.cap(1).toInt(); - if (msvcVersion < 2012) - return QLatin1String("5.0"); - else - return QLatin1String("5.1"); - } - - return qt.qtMajorVersion < 5 ? QLatin1String("5.0") : QLatin1String("5.1"); -} - -static bool checkForStaticBuild(const QtEnvironment &qt) -{ - if (qt.qtMajorVersion >= 5) - return qt.qtConfigItems.contains(QLatin1String("static")); - if (qt.frameworkBuild) - return false; // there are no Qt4 static frameworks - const bool isWin = qt.mkspecName.startsWith(QLatin1String("win")); - const QDir libdir(isWin ? qt.binaryPath : qt.libraryPath); - const QStringList coreLibFiles - = libdir.entryList(QStringList(QLatin1String("*Core*")), QDir::Files); - if (coreLibFiles.empty()) - throw ErrorInfo(Internal::Tr::tr("Could not determine whether Qt is a static build.")); - for (const QString &fileName : coreLibFiles) { - if (QLibrary::isLibrary(fileName)) - return false; - } - return true; -} - -static QStringList fillEntryPointLibs(const QtEnvironment &qtEnvironment, const Version &qtVersion, - bool debug) -{ - QStringList result; - const bool isMinGW = qtEnvironment.isForMinGw(); - - // Some Linux distributions rename the qtmain library. - QStringList qtMainCandidates(QLatin1String("qtmain")); - if (isMinGW && qtEnvironment.qtMajorVersion == 5) - qtMainCandidates << QLatin1String("qt5main"); - - for (const QString &baseNameCandidate : qtMainCandidates) { - QString qtmain = qtEnvironment.libraryPath + QLatin1Char('/'); - if (isMinGW) - qtmain += QLatin1String("lib"); - qtmain += baseNameCandidate + qtEnvironment.qtLibInfix; - if (debug) - qtmain += QLatin1Char('d'); - if (isMinGW) { - qtmain += QLatin1String(".a"); - } else { - qtmain += QLatin1String(".lib"); - if (qtVersion >= Version(5, 4, 0)) - result << QLatin1String("Shell32.lib"); - } - if (QFile::exists(qtmain)) { - result << qtmain; - break; - } - } - if (result.isEmpty()) { - qDebug("Warning: Could not find the qtmain library. " - "You will not be able to link Qt applications."); - } - return result; -} - -void doSetupQtProfile(const QString &profileName, Settings *settings, - const QtEnvironment &_qtEnvironment) -{ - QtEnvironment qtEnvironment = _qtEnvironment; - qtEnvironment.staticBuild = checkForStaticBuild(qtEnvironment); - - // determine whether user apps require C++11 - if (qtEnvironment.qtConfigItems.contains(QLatin1String("c++11")) && qtEnvironment.staticBuild) - qtEnvironment.configItems.push_back(QLatin1String("c++11")); - - // Set the minimum operating system versions appropriate for this Qt version - qtEnvironment.windowsVersion = guessMinimumWindowsVersion(qtEnvironment); - if (!qtEnvironment.windowsVersion.isEmpty()) { // Is target OS Windows? - const Version qtVersion = Version(qtEnvironment.qtMajorVersion, - qtEnvironment.qtMinorVersion, - qtEnvironment.qtPatchVersion); - if (qtEnvironment.buildVariant.contains(QLatin1String("debug"))) { - qtEnvironment.entryPointLibsDebug = fillEntryPointLibs(qtEnvironment, qtVersion, - true); - } - if (qtEnvironment.buildVariant.contains(QLatin1String("release"))) { - qtEnvironment.entryPointLibsRelease = fillEntryPointLibs(qtEnvironment, qtVersion, - false); - } - } else if (qtEnvironment.mkspecPath.contains(QLatin1String("macx"))) { - if (qtEnvironment.qtMajorVersion >= 5) { - QFile qmakeConf(qtEnvironment.mkspecPath + QStringLiteral("/qmake.conf")); - if (qmakeConf.open(QIODevice::ReadOnly)) { - static const std::regex re( - "^QMAKE_(MACOSX|IOS|TVOS|WATCHOS)_DEPLOYMENT_TARGET\\s*=\\s*(.*)\\s*$"); - while (!qmakeConf.atEnd()) { - std::smatch match; - const auto line = qmakeConf.readLine().trimmed().toStdString(); - if (std::regex_match(line, match, re)) { - const auto platform = QString::fromStdString(match[1]); - const auto version = QString::fromStdString(match[2]); - if (platform == QStringLiteral("MACOSX")) - qtEnvironment.macosVersion = version; - else if (platform == QStringLiteral("IOS")) - qtEnvironment.iosVersion = version; - else if (platform == QStringLiteral("TVOS")) - qtEnvironment.tvosVersion = version; - else if (platform == QStringLiteral("WATCHOS")) - qtEnvironment.watchosVersion = version; - } - } - } - - const bool isMac = qtEnvironment.mkspecName != QStringLiteral("macx-ios-clang") - && qtEnvironment.mkspecName != QStringLiteral("macx-tvos-clang") - && qtEnvironment.mkspecName != QStringLiteral("macx-watchos-clang"); - if (isMac) { - // Qt 5.0.x placed the minimum version in a different file - if (qtEnvironment.macosVersion.isEmpty()) { - qtEnvironment.macosVersion = QLatin1String("10.6"); - } - - // If we're using C++11 with libc++, make sure the deployment target is >= 10.7 - if (Version::fromString(qtEnvironment.macosVersion) < Version(10, 7) - && qtEnvironment.qtConfigItems.contains(QLatin1String("c++11"))) - qtEnvironment.macosVersion = QLatin1String("10.7"); - } - } else if (qtEnvironment.qtMajorVersion == 4 && qtEnvironment.qtMinorVersion >= 6) { - QDir qconfigDir; - if (qtEnvironment.frameworkBuild) { - qconfigDir.setPath(qtEnvironment.libraryPath); - qconfigDir.cd(QLatin1String("QtCore.framework/Headers")); - } else { - qconfigDir.setPath(qtEnvironment.includePath); - qconfigDir.cd(QLatin1String("Qt")); - } - QFile qconfig(qconfigDir.absoluteFilePath(QLatin1String("qconfig.h"))); - if (qconfig.open(QIODevice::ReadOnly)) { - bool qtCocoaBuild = false; - QTextStream ts(&qconfig); - QString line; - do { - line = ts.readLine(); - if (QRegExp(QLatin1String("\\s*#define\\s+QT_MAC_USE_COCOA\\s+1\\s*"), - Qt::CaseSensitive).exactMatch(line)) { - qtCocoaBuild = true; - break; - } - } while (!line.isNull()); - - if (ts.status() == QTextStream::Ok) { - qtEnvironment.macosVersion = qtCocoaBuild ? QLatin1String("10.5") - : QLatin1String("10.4"); - } - } - - if (qtEnvironment.macosVersion.isEmpty()) { - throw ErrorInfo(Internal::Tr::tr("Error reading qconfig.h; could not determine " - "whether Qt is using Cocoa or Carbon")); - } - } - } else if (qtEnvironment.mkspecPath.contains(QLatin1String("android"))) { - if (qtEnvironment.qtMajorVersion >= 5) - qtEnvironment.androidVersion = QLatin1String("2.3"); - else if (qtEnvironment.qtMajorVersion == 4 && qtEnvironment.qtMinorVersion >= 8) - qtEnvironment.androidVersion = QLatin1String("1.6"); // Necessitas - } - - Profile profile(profileName, settings); - profile.removeProfile(); - createModules(profile, settings, qtEnvironment); -} - -QString qbsTargetPlatformFromQtMkspec(const QtEnvironment &qtEnv) -{ - QString mkspec = qtEnv.mkspecName; - int idx = mkspec.lastIndexOf(QLatin1Char('/')); - if (idx != -1) - mkspec = mkspec.mid(idx + 1); - if (mkspec.startsWith(QLatin1String("aix-"))) - return QLatin1String("aix"); - if (mkspec.startsWith(QLatin1String("android-"))) - return QLatin1String("android"); - if (mkspec.startsWith(QLatin1String("cygwin-"))) - return QLatin1String("windows"); - if (mkspec.startsWith(QLatin1String("darwin-"))) - return QLatin1String("macos"); - if (mkspec.startsWith(QLatin1String("freebsd-"))) - return QLatin1String("freebsd"); - if (mkspec.startsWith(QLatin1String("haiku-"))) - return QLatin1String("haiku"); - if (mkspec.startsWith(QLatin1String("hpux-")) || mkspec.startsWith(QLatin1String("hpuxi-"))) - return QLatin1String("hpux"); - if (mkspec.startsWith(QLatin1String("hurd-"))) - return QLatin1String("hurd"); - if (mkspec.startsWith(QLatin1String("integrity-"))) - return QLatin1String("integrity"); - if (mkspec.startsWith(QLatin1String("linux-"))) - return QLatin1String("linux"); - if (mkspec.startsWith(QLatin1String("macx-"))) { - if (mkspec.startsWith(QLatin1String("macx-ios-"))) - return QLatin1String("ios"); - if (mkspec.startsWith(QLatin1String("macx-tvos-"))) - return QLatin1String("tvos"); - if (mkspec.startsWith(QLatin1String("macx-watchos-"))) - return QLatin1String("watchos"); - return QLatin1String("macos"); - } - if (mkspec.startsWith(QLatin1String("netbsd-"))) - return QLatin1String("netbsd"); - if (mkspec.startsWith(QLatin1String("openbsd-"))) - return QLatin1String("openbsd"); - if (mkspec.startsWith(QLatin1String("qnx-"))) - return QLatin1String("qnx"); - if (mkspec.startsWith(QLatin1String("solaris-"))) - return QLatin1String("solaris"); - if (mkspec.startsWith(QLatin1String("vxworks-"))) - return QLatin1String("vxworks"); - if (qtEnv.targetsDesktopWindows() || mkspec.startsWith(QLatin1String("winrt-"))) - return QLatin1String("windows"); - return QString(); -} - -ErrorInfo setupQtProfile(const QString &profileName, Settings *settings, - const QtEnvironment &qtEnvironment) -{ - try { - doSetupQtProfile(profileName, settings, qtEnvironment); - return ErrorInfo(); - } catch (const ErrorInfo &e) { - return e; - } -} - -} // namespace qbs diff --git a/src/lib/qtprofilesetup/qtprofilesetup.h b/src/lib/qtprofilesetup/qtprofilesetup.h deleted file mode 100644 index f28733a1b..000000000 --- a/src/lib/qtprofilesetup/qtprofilesetup.h +++ /dev/null @@ -1,59 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qbs. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** 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_SETUPQTPROFILE_H -#define QBS_SETUPQTPROFILE_H - -#include "qtenvironment.h" - -#include - -#include - -namespace qbs { -class ErrorInfo; -class Settings; - -QBS_EXPORT QString qbsTargetPlatformFromQtMkspec(const QtEnvironment &qtEnv); - -QBS_EXPORT ErrorInfo setupQtProfile(const QString &profileName, Settings *settings, - const QtEnvironment &qtEnvironment); - -} // namespace qbs - -#endif // Include guard. diff --git a/src/lib/qtprofilesetup/qtprofilesetup.pro b/src/lib/qtprofilesetup/qtprofilesetup.pro deleted file mode 100644 index a32ff97aa..000000000 --- a/src/lib/qtprofilesetup/qtprofilesetup.pro +++ /dev/null @@ -1,31 +0,0 @@ -TARGET = qbsqtprofilesetup -include(../library.pri) -include(../corelib/use_corelib.pri) - -CONFIG -= qtquickcompiler - -HEADERS = \ - qtenvironment.h \ - qtmoduleinfo.h \ - qtmsvctools.h \ - qtprofilesetup.h - -SOURCES = \ - qtmoduleinfo.cpp \ - qtmsvctools.cpp \ - qtprofilesetup.cpp - -RESOURCES = templates.qrc - -!qbs_no_dev_install { - header.files = \ - qtenvironment.h \ - qtmsvctools.h \ - qtprofilesetup.h - header.path = $${QBS_INSTALL_PREFIX}/include/qbs - use_pri.files = use_installed_qtprofilesetup.pri - use_pri.path = $${header.path} - INSTALLS += header use_pri -} - -OTHER_FILES += templates/* diff --git a/src/lib/qtprofilesetup/qtprofilesetup.qbs b/src/lib/qtprofilesetup/qtprofilesetup.qbs deleted file mode 100644 index 8c8b77020..000000000 --- a/src/lib/qtprofilesetup/qtprofilesetup.qbs +++ /dev/null @@ -1,31 +0,0 @@ -import qbs - -QbsLibrary { - name: "qbsqtprofilesetup" - Depends { name: "qbscore" } - - Group { - name: "Public API headers" - files: [ - "qtenvironment.h", - "qtprofilesetup.h", - "qtmsvctools.h", - "use_installed_qtprofilesetup.pri", - ] - qbs.install: qbsbuildconfig.installApiHeaders - qbs.installDir: headerInstallPrefix - } - - files: [ - "qtprofilesetup.cpp", - "qtmoduleinfo.cpp", - "qtmoduleinfo.h", - "qtmsvctools.cpp", - "templates.qrc", - "templates/*" - ] - - Export { - Depends { name: "qbscore" } - } -} diff --git a/src/lib/qtprofilesetup/templates.qrc b/src/lib/qtprofilesetup/templates.qrc deleted file mode 100644 index 35bddf8d7..000000000 --- a/src/lib/qtprofilesetup/templates.qrc +++ /dev/null @@ -1,22 +0,0 @@ - - - templates/core.qbs - templates/gui.qbs - templates/module.qbs - templates/QtModule.qbs - templates/moc.js - templates/plugin.qbs - templates/qdoc.js - templates/QtPlugin.qbs - templates/dbus.js - templates/dbus.qbs - templates/scxml.qbs - templates/qml.qbs - templates/qml.js - templates/qmlcache.qbs - templates/quick.js - templates/quick.qbs - templates/plugin_support.qbs - templates/android_support.qbs - - diff --git a/src/lib/qtprofilesetup/templates/QtModule.qbs b/src/lib/qtprofilesetup/templates/QtModule.qbs deleted file mode 100644 index aa7c1d15a..000000000 --- a/src/lib/qtprofilesetup/templates/QtModule.qbs +++ /dev/null @@ -1,86 +0,0 @@ -import 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. - // 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 - version: Qt.core.version - 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.frameworkPaths: mFrameworkPaths - } -} diff --git a/src/lib/qtprofilesetup/templates/QtPlugin.qbs b/src/lib/qtprofilesetup/templates/QtPlugin.qbs deleted file mode 100644 index 23a6795f3..000000000 --- a/src/lib/qtprofilesetup/templates/QtPlugin.qbs +++ /dev/null @@ -1,49 +0,0 @@ -import 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.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" - } - - 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; - } - } -} diff --git a/src/lib/qtprofilesetup/templates/android_support.qbs b/src/lib/qtprofilesetup/templates/android_support.qbs deleted file mode 100644 index 79276a494..000000000 --- a/src/lib/qtprofilesetup/templates/android_support.qbs +++ /dev/null @@ -1,291 +0,0 @@ -import qbs.File -import qbs.FileInfo -import qbs.ModUtils -import qbs.TextFile -import qbs.Utilities - -Module { - property bool useMinistro: false - property string qmlRootDir: product.sourceDirectory - property stringList extraPrefixDirs - property stringList deploymentDependencies // qmake: ANDROID_DEPLOYMENT_DEPENDENCIES - property stringList extraPlugins // qmake: ANDROID_EXTRA_PLUGINS - property bool verboseAndroidDeployQt: false - - property string _androidDeployQtFilePath: FileInfo.joinPaths(_qtInstallDir, "bin", - "androiddeployqt") - property string _qtInstallDir - property bool _enableSdkSupport: product.type && product.type.contains("android.apk") - && !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") - - Depends { name: "Android.sdk"; condition: _enableSdkSupport } - Depends { name: "Android.ndk"; condition: _enableNdkSupport } - Depends { name: "java"; condition: _enableSdkSupport } - - Properties { - condition: _enableNdkSupport && qbs.toolchain.contains("clang") - Android.ndk.appStl: "c++_shared" - } - Properties { - condition: _enableNdkSupport && !qbs.toolchain.contains("clang") - Android.ndk.appStl: "gnustl_shared" - } - Properties { - condition: _enableSdkSupport - Android.sdk.customManifestProcessing: true - java._tagJniHeaders: false // prevent rule cycle - } - - Rule { - condition: _enableSdkSupport - multiplex: true - property stringList inputTags: "android.nativelibrary" - inputsFromDependencies: inputTags - inputs: product.aggregate ? [] : inputTags - Artifact { - filePath: "androiddeployqt.json" - fileTags: "qt_androiddeployqt_input" - } - prepare: { - var cmd = new JavaScriptCommand(); - cmd.description = "creating " + output.fileName; - cmd.sourceCode = function() { - var theBinary; - var nativeLibs = inputs["android.nativelibrary"]; - if (nativeLibs.length === 1) { - theBinary = nativeLibs[0]; - } else { - for (i = 0; i < nativeLibs.length; ++i) { - var candidate = nativeLibs[i]; - if (!candidate.fileName.contains(candidate.product.targetName)) - continue; - if (!theBinary) { - theBinary = candidate; - continue; - } - if (theBinary.product.name === product.name - && candidate.product.name !== product.name) { - continue; // We already have a better match. - } - if (candidate.product.name === product.name - && theBinary.product.name !== product.name) { - theBinary = candidate; // The new candidate is a better match. - 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.",'); - 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 + '",'); - var toolPrefix = theBinary.cpp.toolchainTriple; - var toolchainPrefix = toolPrefix.startsWith("i686-") ? "x86" : toolPrefix; - f.writeLine('"toolchain-prefix": "' + toolchainPrefix + '",'); - f.writeLine('"tool-prefix": "' + toolPrefix + '",'); - f.writeLine('"toolchain-version": "' + theBinary.Android.ndk.toolchainVersion - + '",'); - f.writeLine('"ndk-host": "' + theBinary.Android.ndk.hostArch + '",'); - f.writeLine('"target-architecture": "' + theBinary.Android.ndk.abi + '",'); - 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 prefixDirs = product.Qt.android_support.extraPrefixDirs; - if (prefixDirs && prefixDirs.length > 0) - f.writeLine('"extraPrefixDirs": ' + JSON.stringify(prefixDirs) + ','); - if (Array.isArray(product.qmlImportPaths) && product.qmlImportPaths.length > 0) - f.writeLine('"qml-import-paths": "' + product.qmlImportPaths.join(',') + '",'); - f.writeLine('"application-binary": "' + theBinary.filePath + '"'); - f.writeLine("}"); - f.close(); - }; - return cmd; - } - } - - // We use the manifest template from the Qt installation if and only if the project - // does not provide a manifest file. - Rule { - condition: _enableSdkSupport - multiplex: true - requiresInputs: false - inputs: "android.manifest" - excludedInputs: "qt.android_manifest" - outputFileTags: ["android.manifest", "qt.android_manifest"] - outputArtifacts: { - if (inputs["android.manifest"]) - return []; - return [{ - filePath: "qt_manifest/AndroidManifest.xml", - fileTags: ["android.manifest", "qt.android_manifest"] - }]; - } - prepare: { - 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; - } - } - - Rule { - condition: _enableSdkSupport - multiplex: true - inputs: ["qt_androiddeployqt_input", "android.manifest_processed"] - outputFileTags: [ - "android.manifest_final", "android.resources", "android.assets", "bundled_jar", - "android.deployqt_list", - ] - outputArtifacts: { - var artifacts = [ - { - 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" - }, - - ]; - if (!product.Qt.android_support.useMinistro) { - artifacts.push({ - filePath: FileInfo.joinPaths(product.java.classFilesDir, "QtAndroid.jar"), - fileTags: ["bundled_jar"] - }); - } - return artifacts; - } - prepare: { - 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"); - try { - File.remove(FileInfo.path(outputs["android.assets"][0].filePath)); - } catch (e) { - } - }; - var androidDeployQtArgs = [ - "--output", product.Qt.android_support._deployQtOutDir, - "--input", inputs["qt_androiddeployqt_input"][0].filePath, "--aux-mode", - "--deployment", product.Qt.android_support.useMinistro ? "ministro" : "bundled", - "--android-platform", product.Android.sdk.platform, - ]; - if (product.Qt.android_support.verboseAndroidDeployQt) - args.push("--verbose"); - var androidDeployQtCmd = new Command( - product.Qt.android_support._androidDeployQtFilePath, androidDeployQtArgs); - androidDeployQtCmd.description = "running androiddeployqt"; - - // 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 outout"; - moveCmd.sourceCode = function() { - File.move(product.Qt.android_support._deployQtOutDir + "/AndroidManifest.xml", - outputs["android.manifest_final"][0].filePath); - var libsDir = product.Qt.android_support._deployQtOutDir + "/libs"; - var libDir = product.Android.sdk.apkContentsDir + "/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]); - } - }; - return [copyCmd, androidDeployQtCmd, moveCmd]; - } - } - - Group { - condition: Qt.android_support._enableSdkSupport - name: "helper sources from qt" - prefix: Qt.android_support._templatesBaseDir + "/java/" - Android.sdk.aidlSearchPaths: prefix + "src" - files: [ - "**/*.java", - "**/*.aidl", - ] - } - - validate: { - if (Utilities.versionCompare(version, "5.12") < 0) - throw ModUtils.ModuleError("Cannot use Qt " + version + " with Android. " - + "Version 5.12 or later is required."); - } -} diff --git a/src/lib/qtprofilesetup/templates/core.qbs b/src/lib/qtprofilesetup/templates/core.qbs deleted file mode 100644 index b2f05d8e9..000000000 --- a/src/lib/qtprofilesetup/templates/core.qbs +++ /dev/null @@ -1,510 +0,0 @@ -import qbs.FileInfo -import qbs.ModUtils -import qbs.TextFile -import qbs.Utilities -import qbs.Xml -import "moc.js" as Moc -import "qdoc.js" as Qdoc - -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.android_support"; condition: qbs.targetOS.contains("android") } - Properties { - condition: qbs.targetOS.contains("android") - Qt.android_support._qtInstallDir: FileInfo.path(binPath) - Qt.android_support.version: version - } - - version: @version@ - property stringList architectures: @archs@ - property string targetPlatform: @targetPlatform@ - property string libInfix: @libInfix@ - property stringList config: @config@ - property stringList qtConfig: @qtConfig@ - property path binPath: @binPath@ - property path incPath: @incPath@ - property path libPath: @libPath@ - 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 qdocName: versionMajor >= 5 ? "qdoc" : "qdoc3" - property stringList qdocEnvironment - property path docPath: @docPath@ - 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 stringList pluginMetaData: [] - property bool enableKeywords: true - - property stringList availableBuildVariants: @availableBuildVariants@ - property string qtBuildVariant: { - if (availableBuildVariants.contains(qbs.buildVariant)) - return qbs.buildVariant; - 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 stringList coreLibPaths: @libraryPaths@ - - // 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" - } - - cpp.entryPoint: qbs.targetOS.containsAny(["ios", "tvos"]) - && Utilities.versionCompare(version, "5.6.0") >= 0 - ? "_qt_main_wrapper" - : undefined - cpp.cxxLanguageVersion: Utilities.versionCompare(version, "5.7.0") >= 0 ? "c++11" : original - 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 derived - // from the build variant "release" - if (!qbs.debugInformation) - 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"); - } - return defines; - } - cpp.driverFlags: { - var flags = []; - if (qbs.toolchain.contains("gcc")) { - if (config.contains("sanitize_address")) - flags.push("-fsanitize=address"); - 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: { - var paths = @includes@; - paths.push(mkspecPath, generatedHeadersDir); - return paths; - } - 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.frameworkPaths: 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: qbs.targetOS.contains('linux') ? [libPath] : undefined - cpp.runtimeLibrary: qbs.toolchain.contains("msvc") - ? config.contains("static_runtime") ? "static" : "dynamic" - : original - cpp.positionIndependentCode: versionMajor >= 5 ? true : undefined - cpp.cxxFlags: { - var flags = []; - if (qbs.toolchain.contains('msvc')) { - if (versionMajor < 5) - flags.push('/Zc:wchar_t-'); - } - - return flags; - } - cpp.cxxStandardLibrary: { - if (qbs.targetOS.contains('darwin') && qbs.toolchain.contains('clang') - && config.contains('c++11')) - return "libc++"; - return original; - } - cpp.minimumWindowsVersion: @minWinVersion@ - cpp.minimumMacosVersion: @minMacVersion@ - cpp.minimumIosVersion: @minIosVersion@ - cpp.minimumTvosVersion: @minTvosVersion@ - cpp.minimumWatchosVersion: @minWatchosVersion@ - cpp.minimumAndroidVersion: @minAndroidVersion@ - - // 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"] - - 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 - - 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"] - 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"] - 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"] - } - prepare: { - var cmd = new JavaScriptCommand(); - cmd.description = "creating " + output.fileName; - cmd.highlight = "codegen"; - cmd.sourceCode = function() { - ModUtils.mergeCFiles(inputs["moc_cpp"], output.filePath); - }; - return [cmd]; - } - } - - 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: { - 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]; - } - } - - Rule { - inputs: ["qrc"] - outputFileTags: ["cpp", "cpp_intermediate_object"] - outputArtifacts: { - var artifact = { - filePath: "qrc_" + input.completeBaseName + ".cpp", - fileTags: ["cpp"] - }; - if (input.Qt.core.enableBigResources) - artifact.fileTags.push("cpp_intermediate_object"); - return [artifact]; - } - prepare: { - var args = [input.filePath, - "-name", FileInfo.completeBaseName(input.filePath), - "-o", output.filePath]; - if (input.Qt.core.enableBigResources) - args.push("-pass", "1"); - var cmd = new Command(product.Qt.core.binPath + '/rcc', args); - cmd.description = "rcc " - + (input.Qt.core.enableBigResources ? "(pass 1) " : "") - + input.fileName; - cmd.highlight = 'codegen'; - return cmd; - } - } - - Rule { - inputs: ["intermediate_obj"] - Artifact { - filePath: input.completeBaseName + ".2.o" - fileTags: ["obj"] - } - prepare: { - 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(product.Qt.core.binPath + '/rcc', - [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; - } - } - - 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: { - 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; - } - } - - Rule { - inputs: "qdocconf-main" - explicitlyDependsOn: ["qdoc", "qdocconf"] - - outputFileTags: ModUtils.allFileTags(Qdoc.qdocFileTaggers()) - outputArtifacts: Qdoc.outputArtifacts(product, input) - - prepare: { - var outputDir = product.Qt.core.qdocOutputDir; - var args = Qdoc.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; - } - } - - Rule { - inputs: "qhp" - auxiliaryInputs: ModUtils.allFileTags(Qdoc.qdocFileTaggers()) - .filter(function(tag) { return tag !== "qhp"; }) - - Artifact { - filePath: input.completeBaseName + ".qch" - fileTags: ["qch"] - } - - prepare: { - 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.binPath + "/qhelpgenerator", args); - cmd.description = 'qhelpgenerator ' + input.fileName; - cmd.highlight = 'filegen'; - cmd.stdoutFilterFunction = function(output) { - return ""; - }; - return cmd; - } - } - - @additionalContent@ -} diff --git a/src/lib/qtprofilesetup/templates/dbus.js b/src/lib/qtprofilesetup/templates/dbus.js deleted file mode 100644 index 0674bf684..000000000 --- a/src/lib/qtprofilesetup/templates/dbus.js +++ /dev/null @@ -1,61 +0,0 @@ -/**************************************************************************** -** -** 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"); - -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]; -} diff --git a/src/lib/qtprofilesetup/templates/dbus.qbs b/src/lib/qtprofilesetup/templates/dbus.qbs deleted file mode 100644 index 6556e2c9b..000000000 --- a/src/lib/qtprofilesetup/templates/dbus.qbs +++ /dev/null @@ -1,74 +0,0 @@ -import qbs.FileInfo -import qbs.ModUtils -import "../QtModule.qbs" as QtModule -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"] - } - - prepare: { - return 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"] - } - - prepare: { - return DBus.createCommands(product, input, outputs, "-p"); - } - } - - 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.includePaths: @includes@ - cpp.libraryPaths: @libraryPaths@ - - @additionalContent@ -} - diff --git a/src/lib/qtprofilesetup/templates/gui.qbs b/src/lib/qtprofilesetup/templates/gui.qbs deleted file mode 100644 index eb69e0cad..000000000 --- a/src/lib/qtprofilesetup/templates/gui.qbs +++ /dev/null @@ -1,65 +0,0 @@ -import qbs.FileInfo -import qbs.ModUtils -import '../QtModule.qbs' as QtModule - -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"] - } - - prepare: { - var cmd = new Command(ModUtils.moduleProperty(product, "binPath") + '/' - + ModUtils.moduleProperty(product, "uicName"), - [input.filePath, '-o', output.filePath]) - cmd.description = 'uic ' + input.fileName; - cmd.highlight = 'codegen'; - return cmd; - } - } - - property string defaultQpaPlugin: @defaultQpaPlugin@ - 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.defines: @defines@ - cpp.includePaths: @includes@ - cpp.libraryPaths: @libraryPaths@ - - Properties { - condition: Qt.core.staticBuild && qbs.targetOS.contains("ios") - cpp.frameworks: base.concat(["UIKit", "QuartzCore", "CoreText", "CoreGraphics", - "Foundation", "CoreFoundation", "AudioToolbox"]) - } - cpp.frameworks: base - @additionalContent@ -} - diff --git a/src/lib/qtprofilesetup/templates/moc.js b/src/lib/qtprofilesetup/templates/moc.js deleted file mode 100644 index aa67766b9..000000000 --- a/src/lib/qtprofilesetup/templates/moc.js +++ /dev/null @@ -1,102 +0,0 @@ -/**************************************************************************** -** -** 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"); - -function args(product, input, outputFileName) -{ - var defines = product.cpp.compilerDefinesByLanguage; - if (input.fileTags.contains("objcpp")) - defines = ModUtils.flattenDictionary(defines["objcpp"]) || []; - else if (input.fileTags.contains("cpp")) - 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 = []; - 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) -{ - return product.Qt.core.binPath + '/' + 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"); - } - return [artifact]; -} - -function commands(project, product, inputs, outputs, input, output) -{ - var cmd = new Command(fullPath(product), args(product, input, output.filePath)); - cmd.description = 'moc ' + input.fileName; - cmd.highlight = 'codegen'; - return cmd; -} diff --git a/src/lib/qtprofilesetup/templates/module.qbs b/src/lib/qtprofilesetup/templates/module.qbs deleted file mode 100644 index b09f79a87..000000000 --- a/src/lib/qtprofilesetup/templates/module.qbs +++ /dev/null @@ -1,30 +0,0 @@ -import '../QtModule.qbs' as QtModule - -QtModule { - qtModuleName: @name@ - Depends { name: "Qt"; submodules: @dependencies@} - - 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.includePaths: @includes@ - cpp.libraryPaths: @libraryPaths@ - @additionalContent@ -} diff --git a/src/lib/qtprofilesetup/templates/plugin.qbs b/src/lib/qtprofilesetup/templates/plugin.qbs deleted file mode 100644 index e73e2a4d9..000000000 --- a/src/lib/qtprofilesetup/templates/plugin.qbs +++ /dev/null @@ -1,27 +0,0 @@ -import '../QtPlugin.qbs' as QtPlugin - -QtPlugin { - qtModuleName: @name@ - Depends { name: "Qt"; submodules: @dependencies@} - - 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@ -} diff --git a/src/lib/qtprofilesetup/templates/plugin_support.qbs b/src/lib/qtprofilesetup/templates/plugin_support.qbs deleted file mode 100644 index 13d95c383..000000000 --- a/src/lib/qtprofilesetup/templates/plugin_support.qbs +++ /dev/null @@ -1,75 +0,0 @@ -Module { - // Set by user. - property varList pluginsByType - - // 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 (!Array.isArray(newValue)) - 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."; - } - } - } - } - } -} diff --git a/src/lib/qtprofilesetup/templates/qdoc.js b/src/lib/qtprofilesetup/templates/qdoc.js deleted file mode 100644 index 72c161c56..000000000 --- a/src/lib/qtprofilesetup/templates/qdoc.js +++ /dev/null @@ -1,84 +0,0 @@ -/**************************************************************************** -** -** 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")); -} diff --git a/src/lib/qtprofilesetup/templates/qml.js b/src/lib/qtprofilesetup/templates/qml.js deleted file mode 100644 index c7829d81b..000000000 --- a/src/lib/qtprofilesetup/templates/qml.js +++ /dev/null @@ -1,66 +0,0 @@ -var File = require("qbs.File"); -var FileInfo = require("qbs.FileInfo"); -var Process = require("qbs.Process"); -var TextFile = require("qbs.TextFile"); - -function scannerData(scannerFilePath, qmlFiles, qmlPath) -{ - var p; - try { - p = new Process(); - p.exec(scannerFilePath, ["-qmlFiles"].concat(qmlFiles).concat(["-importPath", qmlPath]), - true); - return JSON.parse(p.readStdOut()); - } finally { - if (p) - p.close(); - } -} - -function getPrlRhs(line) -{ - return line.split('=')[1].trim(); -} - -function getLibsForPlugin(pluginData, buildVariant, targetOS, toolchain, qtLibDir) -{ - if (!pluginData.path) - return ""; - var prlFileName = ""; - if (!targetOS.contains("windows")) - prlFileName += "lib"; - prlFileName += pluginData.plugin; - if (buildVariant === "debug" && targetOS.contains("windows")) - prlFileName += "d"; - 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 (line = prlFile.readLine()) { - 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); - otherLibs += otherLibsLine; - } - } - if (!pluginLib) - throw "Malformed prl file '" + prlFilePath + "'."; - return pluginLib + ' ' + otherLibs; - } finally { - prlFile.close(); - } -} diff --git a/src/lib/qtprofilesetup/templates/qml.qbs b/src/lib/qtprofilesetup/templates/qml.qbs deleted file mode 100644 index 2b11abbd5..000000000 --- a/src/lib/qtprofilesetup/templates/qml.qbs +++ /dev/null @@ -1,132 +0,0 @@ -import qbs.TextFile -import '../QtModule.qbs' as QtModule -import "qml.js" as Qml - -QtModule { - qtModuleName: "Qml" - Depends { name: "Qt"; submodules: @dependencies@} - - property string qmlImportScannerName: "qmlimportscanner" - property string qmlImportScannerFilePath: Qt.core.binPath + '/' + qmlImportScannerName - 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" - - hasLibrary: @has_library@ - architectures: @archs@ - targetPlatform: @targetPlatform@ - staticLibsDebug: (isStaticLibrary ? ['@' + pluginListFilePathDebug] : []).concat(@staticLibsDebug@) - staticLibsRelease: (isStaticLibrary ? ['@' + 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.includePaths: @includes@ - cpp.libraryPaths: @libraryPaths@ - @additionalContent@ - - FileTagger { - patterns: ["*.qml"] - fileTags: ["qt.qml.qml"] - } - - FileTagger { - patterns: ["*.js"] - fileTags: ["qt.qml.js"] - } - - Rule { - condition: isStaticLibrary - multiplex: true - requiresInputs: false - inputs: ["qt.qml.qml"] - outputFileTags: ["cpp", "qt.qml.pluginlist"] - outputArtifacts: { - 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; - } - prepare: { - 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); - 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 = { }; - 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.Qt.core.qtBuildVariant, - product.qbs.targetOS, - product.qbs.toolchain, - product.Qt.core.libPath); - listFile.write(libs + ' '); - } - } finally { - if (cppFile) - cppFile.close(); - if (listFile) - listFile.close(); - }; - }; - return [cmd]; - } - } -} diff --git a/src/lib/qtprofilesetup/templates/qmlcache.qbs b/src/lib/qtprofilesetup/templates/qmlcache.qbs deleted file mode 100644 index 9111eb500..000000000 --- a/src/lib/qtprofilesetup/templates/qmlcache.qbs +++ /dev/null @@ -1,85 +0,0 @@ -import 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.binPath, "qmlcachegen") - + (qbs.hostOS.contains("windows") ? ".exe" : "") - 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 - } -} diff --git a/src/lib/qtprofilesetup/templates/quick.js b/src/lib/qtprofilesetup/templates/quick.js deleted file mode 100644 index 4f3da2fb0..000000000 --- a/src/lib/qtprofilesetup/templates/quick.js +++ /dev/null @@ -1,84 +0,0 @@ -/**************************************************************************** -** -** 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"); - -function scanQrc(qrcFilePath) { - var absInputDir = FileInfo.path(qrcFilePath); - var result = []; - var process = new Process(); - try { - var rcc = FileInfo.joinPaths(product.Qt.core.binPath, 'rcc' + product.cpp.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(qrcFilePath) { - var filesInQrc = scanQrc(qrcFilePath); - var qmlJsFiles = filesInQrc.filter(function (filePath) { - return (/\.(js|qml)$/).test(filePath); - } ); - var content = {}; - if (filesInQrc.length - qmlJsFiles.length > 0) { - content.newQrcFileName = qtQuickResourceFileOutputName(input.fileName); - } - content.qmlJsFiles = qmlJsFiles.map(function (filePath) { - return { - input: filePath, - output: qtQuickCompilerOutputName(filePath) - }; - }); - return content; -} diff --git a/src/lib/qtprofilesetup/templates/quick.qbs b/src/lib/qtprofilesetup/templates/quick.qbs deleted file mode 100644 index 5968949c8..000000000 --- a/src/lib/qtprofilesetup/templates/quick.qbs +++ /dev/null @@ -1,211 +0,0 @@ -/**************************************************************************** -** -** 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.TextFile -import qbs.Utilities -import '../QtModule.qbs' as QtModule -import 'quick.js' as QC - -QtModule { - qtModuleName: @name@ - Depends { name: "Qt"; submodules: @dependencies@.concat("qml-private") } - - 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.includePaths: @includes@ - cpp.libraryPaths: @libraryPaths@ - @additionalContent@ - - readonly property bool _compilerIsQmlCacheGen: Utilities.versionCompare(Qt.core.version, - "5.11") >= 0 - readonly property string _generatedLoaderFileName: _compilerIsQmlCacheGen - ? "qmlcache_loader.cpp" - : "qtquickcompiler_loader.cpp" - property string compilerBaseName: (_compilerIsQmlCacheGen ? "qmlcachegen" : "qtquickcompiler") - property string compilerFilePath: FileInfo.joinPaths(Qt.core.binPath, - compilerBaseName + product.cpp.executableSuffix) - property bool compilerAvailable: File.exists(compilerFilePath); - property bool useCompiler: compilerAvailable && !_compilerIsQmlCacheGen - - Scanner { - condition: useCompiler - inputs: 'qt.quick.qrc' - searchPaths: [FileInfo.path(input.filePath)] - scan: QC.scanQrc(input.filePath) - } - - FileTagger { - condition: useCompiler - patterns: "*.qrc" - fileTags: ["qt.quick.qrc"] - priority: 100 - } - - Rule { - condition: useCompiler - inputs: ["qt.quick.qrc"] - Artifact { - filePath: input.fileName + ".json" - fileTags: ["qt.quick.qrcinfo"] - } - prepare: { - var cmd = new JavaScriptCommand(); - cmd.silent = true; - cmd.sourceCode = function() { - var content = QC.contentFromQrc(input.filePath); - content.qrcFilePath = input.filePath; - - var tf = new TextFile(output.filePath, TextFile.WriteOnly); - tf.write(JSON.stringify(content)); - tf.close(); - } - return cmd; - } - } - - Rule { - condition: useCompiler - inputs: ["qt.quick.qrcinfo"] - outputFileTags: ["cpp", "qrc"] - multiplex: true - outputArtifacts: { - 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; - } - prepare: { - 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); - 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; - } - } -} diff --git a/src/lib/qtprofilesetup/templates/scxml.qbs b/src/lib/qtprofilesetup/templates/scxml.qbs deleted file mode 100644 index 7125ec53c..000000000 --- a/src/lib/qtprofilesetup/templates/scxml.qbs +++ /dev/null @@ -1,80 +0,0 @@ -import qbs.FileInfo -import qbs.Utilities -import "../QtModule.qbs" as QtModule - -QtModule { - qtModuleName: "Scxml" - - 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"] - } - - prepare: { - var compilerName = product.moduleProperty("Qt.scxml", "qscxmlcName"); - var compilerPath = FileInfo.joinPaths(input.moduleProperty("Qt.core", "binPath"), - 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]; - } - } - - 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.includePaths: @includes@ - cpp.libraryPaths: @libraryPaths@ - - @additionalContent@ -} diff --git a/src/lib/qtprofilesetup/use_installed_qtprofilesetup.pri b/src/lib/qtprofilesetup/use_installed_qtprofilesetup.pri deleted file mode 100644 index c3fa4a83d..000000000 --- a/src/lib/qtprofilesetup/use_installed_qtprofilesetup.pri +++ /dev/null @@ -1,20 +0,0 @@ -include(use_installed_corelib.pri) - -LIBNAME=qbsqtprofilesetup - -unix:LIBS += -l$${LIBNAME} - -win32 { - CONFIG(debug, debug|release) { - QBSQTPROFILELIB = $${LIBNAME}d$${QBSCORELIBSUFFIX} - } - CONFIG(release, debug|release) { - QBSQTPROFILELIB = $${LIBNAME}$${QBSCORELIBSUFFIX} - } - msvc { - QBSQTPROFILELIB = $${QBSQTPROFILELIB}.lib - } else { - QBSQTPROFILELIB = lib$${QBSQTPROFILELIB} - } - LIBS += $${QBSQTPROFILELIB} -} diff --git a/src/lib/qtprofilesetup/use_qtprofilesetup.pri b/src/lib/qtprofilesetup/use_qtprofilesetup.pri deleted file mode 100644 index 87390fc10..000000000 --- a/src/lib/qtprofilesetup/use_qtprofilesetup.pri +++ /dev/null @@ -1,46 +0,0 @@ -include(../../../qbs_version.pri) -include(../../library_dirname.pri) - -isEmpty(QBSLIBDIR) { - QBSLIBDIR = $${OUT_PWD}/../../../$${QBS_LIBRARY_DIRNAME} -} - -LIBNAME=qbsqtprofilesetup - -unix { - LIBS += -L$${QBSLIBDIR} -l$${LIBNAME} -} - -!qbs_disable_rpath { - linux-*:QMAKE_LFLAGS += -Wl,-z,origin \'-Wl,-rpath,\$\$ORIGIN/../$${QBS_LIBRARY_DIRNAME}\' - macx:QMAKE_LFLAGS += -Wl,-rpath,@loader_path/../$${QBS_LIBRARY_DIRNAME} -} - -!CONFIG(static, static|shared) { - QBSQTPROFILELIBSUFFIX = $${QBS_VERSION_MAJ} -} - -win32 { - CONFIG(debug, debug|release) { - QBSQTPROFILELIB = $${LIBNAME}d$${QBSQTPROFILELIBSUFFIX} - } - CONFIG(release, debug|release) { - QBSQTPROFILELIB = $${LIBNAME}$${QBSQTPROFILELIBSUFFIX} - } - msvc { - LIBS += /LIBPATH:$$QBSLIBDIR - QBSQTPROFILELIB = $${QBSQTPROFILELIB}.lib - LIBS += Shell32.lib - } else { - LIBS += -L$${QBSLIBDIR} - QBSQTPROFILELIB = lib$${QBSQTPROFILELIB} - } - LIBS += $${QBSQTPROFILELIB} -} - -INCLUDEPATH += \ - $$PWD - -CONFIG(static, static|shared) { - DEFINES += QBS_STATIC_LIB -} diff --git a/src/packages/archive/archive.qbs b/src/packages/archive/archive.qbs index 39d762884..7deaddc3a 100644 --- a/src/packages/archive/archive.qbs +++ b/src/packages/archive/archive.qbs @@ -8,7 +8,6 @@ QbsProduct { Depends { name: "qbs_processlauncher" } Depends { name: "qbscore" } Depends { name: "bundledqt" } - Depends { name: "qbsqtprofilesetup" } Depends { name: "qbs documentation" } Depends { name: "qbs resources" } Depends { name: "qbs man page"; condition: qbs.targetOS.contains("unix") } diff --git a/tests/auto/blackbox/tst_blackboxqt.cpp b/tests/auto/blackbox/tst_blackboxqt.cpp index 128c61133..4428ddb1d 100644 --- a/tests/auto/blackbox/tst_blackboxqt.cpp +++ b/tests/auto/blackbox/tst_blackboxqt.cpp @@ -50,15 +50,12 @@ void TestBlackboxQt::validateTestProfile() 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.")); - - const QStringList searchPaths - = qbs::Preferences(s.get(), profileName()).searchPaths( - QDir::cleanPath(QCoreApplication::applicationDirPath())); - for (const auto &searchPath : searchPaths) { - if (QFileInfo(searchPath + "/modules/Qt").isDir()) - 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.")); -- cgit v1.2.3