aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Kandeler <christian.kandeler@qt.io>2019-01-18 16:02:43 +0100
committerChristian Kandeler <christian.kandeler@qt.io>2019-02-12 09:12:39 +0000
commitc4e60ed8283aa7a86e13c09113e7fec6bf41cc42 (patch)
tree6cefbf3ece17e255c3962e69573abc88bef060ef
parent17058d1fc537e40e7dda9d6e48ccfb24ea1220f7 (diff)
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 <joerg.bornemann@qt.io>
-rw-r--r--doc/qbs.qdoc10
-rw-r--r--doc/reference/modules/qt-modules.qdoc16
-rw-r--r--qbs.pro5
-rw-r--r--share/qbs/module-providers/Qt/provider.qbs6
-rw-r--r--share/qbs/module-providers/Qt/setup-qt.js1504
-rw-r--r--share/qbs/module-providers/Qt/templates/QtModule.qbs (renamed from src/lib/qtprofilesetup/templates/QtModule.qbs)0
-rw-r--r--share/qbs/module-providers/Qt/templates/QtPlugin.qbs (renamed from src/lib/qtprofilesetup/templates/QtPlugin.qbs)0
-rw-r--r--share/qbs/module-providers/Qt/templates/android_support.qbs (renamed from src/lib/qtprofilesetup/templates/android_support.qbs)0
-rw-r--r--share/qbs/module-providers/Qt/templates/core.qbs (renamed from src/lib/qtprofilesetup/templates/core.qbs)0
-rw-r--r--share/qbs/module-providers/Qt/templates/dbus.js (renamed from src/lib/qtprofilesetup/templates/dbus.js)0
-rw-r--r--share/qbs/module-providers/Qt/templates/dbus.qbs (renamed from src/lib/qtprofilesetup/templates/dbus.qbs)0
-rw-r--r--share/qbs/module-providers/Qt/templates/gui.qbs (renamed from src/lib/qtprofilesetup/templates/gui.qbs)0
-rw-r--r--share/qbs/module-providers/Qt/templates/moc.js (renamed from src/lib/qtprofilesetup/templates/moc.js)0
-rw-r--r--share/qbs/module-providers/Qt/templates/module.qbs (renamed from src/lib/qtprofilesetup/templates/module.qbs)0
-rw-r--r--share/qbs/module-providers/Qt/templates/plugin.qbs (renamed from src/lib/qtprofilesetup/templates/plugin.qbs)0
-rw-r--r--share/qbs/module-providers/Qt/templates/plugin_support.qbs (renamed from src/lib/qtprofilesetup/templates/plugin_support.qbs)0
-rw-r--r--share/qbs/module-providers/Qt/templates/qdoc.js (renamed from src/lib/qtprofilesetup/templates/qdoc.js)0
-rw-r--r--share/qbs/module-providers/Qt/templates/qml.js (renamed from src/lib/qtprofilesetup/templates/qml.js)0
-rw-r--r--share/qbs/module-providers/Qt/templates/qml.qbs (renamed from src/lib/qtprofilesetup/templates/qml.qbs)0
-rw-r--r--share/qbs/module-providers/Qt/templates/qmlcache.qbs (renamed from src/lib/qtprofilesetup/templates/qmlcache.qbs)0
-rw-r--r--share/qbs/module-providers/Qt/templates/quick.js (renamed from src/lib/qtprofilesetup/templates/quick.js)0
-rw-r--r--share/qbs/module-providers/Qt/templates/quick.qbs (renamed from src/lib/qtprofilesetup/templates/quick.qbs)0
-rw-r--r--share/qbs/module-providers/Qt/templates/scxml.qbs (renamed from src/lib/qtprofilesetup/templates/scxml.qbs)0
-rw-r--r--src/app/qbs-setup-android/android-setup.cpp8
-rw-r--r--src/app/qbs-setup-qt/main.cpp11
-rw-r--r--src/app/qbs-setup-qt/qbs-setup-qt.pro1
-rw-r--r--src/app/qbs-setup-qt/qbs-setup-qt.qbs1
-rw-r--r--src/app/qbs-setup-qt/setupqt.cpp311
-rw-r--r--src/app/qbs-setup-qt/setupqt.h25
-rw-r--r--src/lib/corelib/jsextensions/utilitiesextension.cpp262
-rw-r--r--src/lib/libs.qbs1
-rw-r--r--src/lib/qtprofilesetup/qtenvironment.h101
-rw-r--r--src/lib/qtprofilesetup/qtmoduleinfo.cpp839
-rw-r--r--src/lib/qtprofilesetup/qtmoduleinfo.h115
-rw-r--r--src/lib/qtprofilesetup/qtmsvctools.cpp79
-rw-r--r--src/lib/qtprofilesetup/qtmsvctools.h49
-rw-r--r--src/lib/qtprofilesetup/qtprofilesetup.cpp930
-rw-r--r--src/lib/qtprofilesetup/qtprofilesetup.h59
-rw-r--r--src/lib/qtprofilesetup/qtprofilesetup.pro31
-rw-r--r--src/lib/qtprofilesetup/qtprofilesetup.qbs31
-rw-r--r--src/lib/qtprofilesetup/templates.qrc22
-rw-r--r--src/lib/qtprofilesetup/use_installed_qtprofilesetup.pri20
-rw-r--r--src/lib/qtprofilesetup/use_qtprofilesetup.pri46
-rw-r--r--src/packages/archive/archive.qbs1
-rw-r--r--tests/auto/blackbox/tst_blackboxqt.cpp15
45 files changed, 1906 insertions, 2593 deletions
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/src/lib/qtprofilesetup/templates/QtModule.qbs b/share/qbs/module-providers/Qt/templates/QtModule.qbs
index aa7c1d15a..aa7c1d15a 100644
--- a/src/lib/qtprofilesetup/templates/QtModule.qbs
+++ b/share/qbs/module-providers/Qt/templates/QtModule.qbs
diff --git a/src/lib/qtprofilesetup/templates/QtPlugin.qbs b/share/qbs/module-providers/Qt/templates/QtPlugin.qbs
index 23a6795f3..23a6795f3 100644
--- a/src/lib/qtprofilesetup/templates/QtPlugin.qbs
+++ b/share/qbs/module-providers/Qt/templates/QtPlugin.qbs
diff --git a/src/lib/qtprofilesetup/templates/android_support.qbs b/share/qbs/module-providers/Qt/templates/android_support.qbs
index 79276a494..79276a494 100644
--- a/src/lib/qtprofilesetup/templates/android_support.qbs
+++ b/share/qbs/module-providers/Qt/templates/android_support.qbs
diff --git a/src/lib/qtprofilesetup/templates/core.qbs b/share/qbs/module-providers/Qt/templates/core.qbs
index b2f05d8e9..b2f05d8e9 100644
--- a/src/lib/qtprofilesetup/templates/core.qbs
+++ b/share/qbs/module-providers/Qt/templates/core.qbs
diff --git a/src/lib/qtprofilesetup/templates/dbus.js b/share/qbs/module-providers/Qt/templates/dbus.js
index 0674bf684..0674bf684 100644
--- a/src/lib/qtprofilesetup/templates/dbus.js
+++ b/share/qbs/module-providers/Qt/templates/dbus.js
diff --git a/src/lib/qtprofilesetup/templates/dbus.qbs b/share/qbs/module-providers/Qt/templates/dbus.qbs
index 6556e2c9b..6556e2c9b 100644
--- a/src/lib/qtprofilesetup/templates/dbus.qbs
+++ b/share/qbs/module-providers/Qt/templates/dbus.qbs
diff --git a/src/lib/qtprofilesetup/templates/gui.qbs b/share/qbs/module-providers/Qt/templates/gui.qbs
index eb69e0cad..eb69e0cad 100644
--- a/src/lib/qtprofilesetup/templates/gui.qbs
+++ b/share/qbs/module-providers/Qt/templates/gui.qbs
diff --git a/src/lib/qtprofilesetup/templates/moc.js b/share/qbs/module-providers/Qt/templates/moc.js
index aa67766b9..aa67766b9 100644
--- a/src/lib/qtprofilesetup/templates/moc.js
+++ b/share/qbs/module-providers/Qt/templates/moc.js
diff --git a/src/lib/qtprofilesetup/templates/module.qbs b/share/qbs/module-providers/Qt/templates/module.qbs
index b09f79a87..b09f79a87 100644
--- a/src/lib/qtprofilesetup/templates/module.qbs
+++ b/share/qbs/module-providers/Qt/templates/module.qbs
diff --git a/src/lib/qtprofilesetup/templates/plugin.qbs b/share/qbs/module-providers/Qt/templates/plugin.qbs
index e73e2a4d9..e73e2a4d9 100644
--- a/src/lib/qtprofilesetup/templates/plugin.qbs
+++ b/share/qbs/module-providers/Qt/templates/plugin.qbs
diff --git a/src/lib/qtprofilesetup/templates/plugin_support.qbs b/share/qbs/module-providers/Qt/templates/plugin_support.qbs
index 13d95c383..13d95c383 100644
--- a/src/lib/qtprofilesetup/templates/plugin_support.qbs
+++ b/share/qbs/module-providers/Qt/templates/plugin_support.qbs
diff --git a/src/lib/qtprofilesetup/templates/qdoc.js b/share/qbs/module-providers/Qt/templates/qdoc.js
index 72c161c56..72c161c56 100644
--- a/src/lib/qtprofilesetup/templates/qdoc.js
+++ b/share/qbs/module-providers/Qt/templates/qdoc.js
diff --git a/src/lib/qtprofilesetup/templates/qml.js b/share/qbs/module-providers/Qt/templates/qml.js
index c7829d81b..c7829d81b 100644
--- a/src/lib/qtprofilesetup/templates/qml.js
+++ b/share/qbs/module-providers/Qt/templates/qml.js
diff --git a/src/lib/qtprofilesetup/templates/qml.qbs b/share/qbs/module-providers/Qt/templates/qml.qbs
index 2b11abbd5..2b11abbd5 100644
--- a/src/lib/qtprofilesetup/templates/qml.qbs
+++ b/share/qbs/module-providers/Qt/templates/qml.qbs
diff --git a/src/lib/qtprofilesetup/templates/qmlcache.qbs b/share/qbs/module-providers/Qt/templates/qmlcache.qbs
index 9111eb500..9111eb500 100644
--- a/src/lib/qtprofilesetup/templates/qmlcache.qbs
+++ b/share/qbs/module-providers/Qt/templates/qmlcache.qbs
diff --git a/src/lib/qtprofilesetup/templates/quick.js b/share/qbs/module-providers/Qt/templates/quick.js
index 4f3da2fb0..4f3da2fb0 100644
--- a/src/lib/qtprofilesetup/templates/quick.js
+++ b/share/qbs/module-providers/Qt/templates/quick.js
diff --git a/src/lib/qtprofilesetup/templates/quick.qbs b/share/qbs/module-providers/Qt/templates/quick.qbs
index 5968949c8..5968949c8 100644
--- a/src/lib/qtprofilesetup/templates/quick.qbs
+++ b/share/qbs/module-providers/Qt/templates/quick.qbs
diff --git a/src/lib/qtprofilesetup/templates/scxml.qbs b/share/qbs/module-providers/Qt/templates/scxml.qbs
index 7125ec53c..7125ec53c 100644
--- a/src/lib/qtprofilesetup/templates/scxml.qbs
+++ b/share/qbs/module-providers/Qt/templates/scxml.qbs
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 <qtprofilesetup.h>
#include <logging/translator.h>
#include <tools/settings.h>
@@ -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<EnhancedQtEnvironment> qtEnvironments = SetupQt::fetchEnvironments();
+ const std::vector<QtEnvironment> 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 <qtmsvctools.h>
-#include <qtprofilesetup.h>
#include <logging/translator.h>
#include <tools/architectures.h>
#include <tools/hostosinfo.h>
@@ -56,10 +54,10 @@
#include <QtCore/qdir.h>
#include <QtCore/qfileinfo.h>
#include <QtCore/qprocess.h>
-#include <QtCore/qregexp.h>
#include <QtCore/qstringlist.h>
#include <algorithm>
+#include <regex>
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<EnhancedQtEnvironment> SetupQt::fetchEnvironments()
+std::vector<QtEnvironment> SetupQt::fetchEnvironments()
{
- std::vector<EnhancedQtEnvironment> qtEnvironments;
-
+ std::vector<QtEnvironment> 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<QByteArray, QByteArray> 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<QByteArray, QByteArray> 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<std::string, std::string> 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<QByteArray> 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<QByteArray, QByteArray> 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 <typename T> 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<QString>::fromList(
toolchainProfile.value(QLatin1String("qbs.toolchain")).toStringList());
- const auto mkspecToolchainNames = Internal::Set<QString>::fromList(
- qbsToolchainFromQtMkspec(env));
- if (areProfilePropertiesIncompatible(toolchainNames, mkspecToolchainNames)) {
+ const auto qtToolchainNames = Internal::Set<QString>::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<EnhancedQtEnvironment> &qtEnvironments)
+bool SetupQt::checkIfMoreThanOneQtWithTheSameVersion(const Version &qtVersion,
+ const std::vector<QtEnvironment> &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 <qtenvironment.h>
#include <tools/error.h>
+#include <tools/version.h>
#include <QtCore/qcoreapplication.h>
#include <QtCore/qstringlist.h>
@@ -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<EnhancedQtEnvironment> 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<QtEnvironment> fetchEnvironments();
+ static QtEnvironment fetchEnvironment(const QString &qmakePath);
+ static bool checkIfMoreThanOneQtWithTheSameVersion(const Version &qtVersion,
+ const std::vector<QtEnvironment> &qtEnvironments);
+ static void saveToQbsSettings(const QString &qtVersionName, const QtEnvironment &qtEnvironment,
Settings *settings);
- static bool checkIfMoreThanOneQtWithTheSameVersion(const QString &qtVersion,
- const std::vector<EnhancedQtEnvironment> &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 <tools/applecodesignutils.h>
#endif
+#ifdef __APPLE__
+#include <ar.h>
+#include <mach/machine.h>
+#include <mach-o/fat.h>
+#include <mach-o/loader.h>
+#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 <tools/msvcinfo.h>
#include <tools/vsenvironmentdetector.h>
@@ -58,6 +78,9 @@
#include <QtCore/qcryptographichash.h>
#include <QtCore/qdir.h>
+#include <QtCore/qendian.h>
+#include <QtCore/qfile.h>
+#include <QtCore/qlibrary.h>
#include <QtScript/qscriptable.h>
#include <QtScript/qscriptengine.h>
@@ -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 <typename T = uint32_t> 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<const T *>(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<char *>(&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<int>(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<char *>(&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<cpu_type_t>(readInt(device, &ok, swap));
+ if (!ok)
+ return QStringList();
+
+ header.cpusubtype = static_cast<cpu_subtype_t>(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 <tools/qbs_export.h>
-#include <tools/version.h>
-
-#include <QtCore/qstringlist.h>
-
-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 <logging/translator.h>
-#include <tools/error.h>
-#include <tools/profile.h>
-#include <tools/qttools.h>
-#include <tools/set.h>
-#include <tools/stlutils.h>
-
-#include <QtCore/qdiriterator.h>
-#include <QtCore/qfile.h>
-#include <QtCore/qhash.h>
-
-#include <algorithm>
-#include <functional>
-#include <map>
-#include <unordered_map>
-
-namespace qbs {
-namespace Internal {
-
-typedef QHash<QString, QString> 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<QtModuleInfo> *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<QString, QString> 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<QtModuleInfo> *modules)
- {
- setupReverseDependencies(modules);
-
- // Traverse the debug variants of modules.
- m_getLibraries = [](QtModuleInfo *module) {
- return std::vector<QStringList *>{
- &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<QStringList *>{
- &module->dynamicLibrariesRelease, &module->staticLibrariesRelease
- };
- };
- m_getLibFilePath = [](QtModuleInfo *module) {
- return module->libFilePathRelease;
- };
- for (QtModuleInfo *module : rootModules)
- traverse(module, QStringList());
- }
-
-private:
- void setupReverseDependencies(QList<QtModuleInfo> *modules)
- {
- std::map<QString, QtModuleInfo *> 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<QtModuleInfo *> roots(QList<QtModuleInfo> *modules)
- {
- std::vector<QtModuleInfo *> 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<QtModuleInfo *, std::vector<QtModuleInfo *>> m_revDeps;
- std::vector<QtModuleInfo *> m_currentPath;
- std::function<std::vector<QStringList *>(QtModuleInfo *)> m_getLibraries;
- std::function<QString(QtModuleInfo *)> m_getLibFilePath;
-};
-
-static void removeDuplicatedDependencyLibs(QList<QtModuleInfo> *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<QString> *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<QString> *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<QByteArray> 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<QtModuleInfo> &modules)
-{
- QtModuleInfo testModule(QLatin1String("QtTest"), QLatin1String("test"),
- QStringList() << QLatin1String("testlib"));
- testModule.hasLibrary = false;
- modules.push_back(testModule);
-}
-
-// See above.
-static void addDesignerComponentsModule(QList<QtModuleInfo> &modules)
-{
- QtModuleInfo module(QLatin1String("QtDesignerComponents"),
- QLatin1String("designercomponents"),
- QStringList() << QLatin1String("designercomponents-private"));
- module.hasLibrary = false;
- modules.push_back(module);
-}
-
-
-QList<QtModuleInfo> allQt4Modules(const QtEnvironment &qtEnvironment)
-{
- // as per http://doc.qt.io/qt-4.8/modules.html + private stuff.
- QList<QtModuleInfo> 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<QtModuleInfo>()
- << 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<QString> nonExistingPrlFiles;
- for (QtModuleInfo &module : modules) {
- if (qtEnvironment.staticBuild)
- module.isStaticLibrary = true;
- module.setupLibraries(qtEnvironment, &nonExistingPrlFiles);
- }
- replaceQtLibNamesWithFilePath(&modules, qtEnvironment);
-
- return modules;
-}
-
-static QList<QByteArray> 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<QByteArray> 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<QByteArray> &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<QtModuleInfo> allQt5Modules(const Profile &profile, const QtEnvironment &qtEnvironment)
-{
- Internal::Set<QString> nonExistingPrlFiles;
- QList<QtModuleInfo> 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 <QtCore/qstringlist.h>
-
-namespace qbs {
-class QtEnvironment;
-class Profile;
-
-namespace Internal {
-
-template<typename T> 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<QString> *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<QString> *nonExistingPrlFiles);
-};
-
-QList<QtModuleInfo> allQt4Modules(const QtEnvironment &qtEnvironment);
-QList<QtModuleInfo> 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 <tools/qbs_export.h>
-#include <tools/version.h>
-
-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 <logging/translator.h>
-#include <tools/architectures.h>
-#include <tools/error.h>
-#include <tools/hostosinfo.h>
-#include <tools/jsliterals.h>
-#include <tools/profile.h>
-#include <tools/settings.h>
-#include <tools/version.h>
-
-#include <QtCore/qdir.h>
-#include <QtCore/qdiriterator.h>
-#include <QtCore/qendian.h>
-#include <QtCore/qfile.h>
-#include <QtCore/qfileinfo.h>
-#include <QtCore/qlibrary.h>
-#include <QtCore/qregexp.h>
-#include <QtCore/qtextstream.h>
-
-#include <queue>
-#include <regex>
-
-#ifdef __APPLE__
-#include <ar.h>
-#include <mach/machine.h>
-#include <mach-o/fat.h>
-#include <mach-o/loader.h>
-#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 <class T>
-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<QByteArray> 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<QString> 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<QByteArray> 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 <typename T = uint32_t> 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<const T *>(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<char *>(&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<int>(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<char *>(&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<cpu_type_t>(readInt(device, &ok, swap));
- if (!ok)
- return QStringList();
-
- header.cpusubtype = static_cast<cpu_subtype_t>(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<int, int> findVariable(const QByteArray &content, int start)
-{
- std::pair<int, int> 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<QByteArray, QByteArray> 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<int, int> 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<QtModuleInfo> 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 <tools/qbs_export.h>
-
-#include <QtCore/qstring.h>
-
-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 @@
-<RCC>
- <qresource prefix="/">
- <file>templates/core.qbs</file>
- <file>templates/gui.qbs</file>
- <file>templates/module.qbs</file>
- <file>templates/QtModule.qbs</file>
- <file>templates/moc.js</file>
- <file>templates/plugin.qbs</file>
- <file>templates/qdoc.js</file>
- <file>templates/QtPlugin.qbs</file>
- <file>templates/dbus.js</file>
- <file>templates/dbus.qbs</file>
- <file>templates/scxml.qbs</file>
- <file>templates/qml.qbs</file>
- <file>templates/qml.js</file>
- <file>templates/qmlcache.qbs</file>
- <file>templates/quick.js</file>
- <file>templates/quick.qbs</file>
- <file>templates/plugin_support.qbs</file>
- <file>templates/android_support.qbs</file>
- </qresource>
-</RCC>
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."));