aboutsummaryrefslogtreecommitdiffstats
path: root/share/qbs/imports/qbs/Probes
diff options
context:
space:
mode:
Diffstat (limited to 'share/qbs/imports/qbs/Probes')
-rw-r--r--share/qbs/imports/qbs/Probes/AndroidNdkProbe.qbs14
-rw-r--r--share/qbs/imports/qbs/Probes/AndroidSdkProbe.qbs29
-rw-r--r--share/qbs/imports/qbs/Probes/BinaryProbe.qbs6
-rw-r--r--share/qbs/imports/qbs/Probes/ClBinaryProbe.qbs71
-rw-r--r--share/qbs/imports/qbs/Probes/ClangClBinaryProbe.qbs73
-rw-r--r--share/qbs/imports/qbs/Probes/ClangClProbe.qbs28
-rw-r--r--share/qbs/imports/qbs/Probes/ConanfileProbe.qbs145
-rw-r--r--share/qbs/imports/qbs/Probes/CosmicProbe.qbs87
-rw-r--r--share/qbs/imports/qbs/Probes/DmcProbe.qbs97
-rw-r--r--share/qbs/imports/qbs/Probes/FrameworkProbe.qbs7
-rw-r--r--share/qbs/imports/qbs/Probes/GccBinaryProbe.qbs41
-rw-r--r--share/qbs/imports/qbs/Probes/GccProbe.qbs11
-rw-r--r--share/qbs/imports/qbs/Probes/GccVersionProbe.qbs4
-rw-r--r--share/qbs/imports/qbs/Probes/IarProbe.qbs31
-rw-r--r--share/qbs/imports/qbs/Probes/IncludeProbe.qbs2
-rw-r--r--share/qbs/imports/qbs/Probes/InnoSetupProbe.qbs27
-rw-r--r--share/qbs/imports/qbs/Probes/JdkProbe.qbs7
-rw-r--r--share/qbs/imports/qbs/Probes/KeilProbe.qbs27
-rw-r--r--share/qbs/imports/qbs/Probes/LibraryProbe.qbs49
-rw-r--r--share/qbs/imports/qbs/Probes/MsvcProbe.qbs5
-rw-r--r--share/qbs/imports/qbs/Probes/NodeJsProbe.qbs3
-rw-r--r--share/qbs/imports/qbs/Probes/NpmProbe.qbs35
-rw-r--r--share/qbs/imports/qbs/Probes/PathProbe.qbs31
-rw-r--r--share/qbs/imports/qbs/Probes/PkgConfigProbe.qbs19
-rw-r--r--share/qbs/imports/qbs/Probes/QbsPkgConfigProbe.qbs64
-rw-r--r--share/qbs/imports/qbs/Probes/QmakeProbe.qbs41
-rw-r--r--share/qbs/imports/qbs/Probes/SdccProbe.qbs44
-rw-r--r--share/qbs/imports/qbs/Probes/TypeScriptProbe.qbs31
-rw-r--r--share/qbs/imports/qbs/Probes/WatcomProbe.qbs98
-rw-r--r--share/qbs/imports/qbs/Probes/XcodeLocationProbe.qbs47
-rw-r--r--share/qbs/imports/qbs/Probes/XcodeProbe.qbs5
-rw-r--r--share/qbs/imports/qbs/Probes/path-probe.js36
-rw-r--r--share/qbs/imports/qbs/Probes/qbs-pkg-config-probe.js118
-rw-r--r--share/qbs/imports/qbs/Probes/qmake-probe.js1256
34 files changed, 2385 insertions, 204 deletions
diff --git a/share/qbs/imports/qbs/Probes/AndroidNdkProbe.qbs b/share/qbs/imports/qbs/Probes/AndroidNdkProbe.qbs
index 4a86ee935..e50d4251a 100644
--- a/share/qbs/imports/qbs/Probes/AndroidNdkProbe.qbs
+++ b/share/qbs/imports/qbs/Probes/AndroidNdkProbe.qbs
@@ -32,12 +32,12 @@
import qbs.Environment
import qbs.File
import qbs.FileInfo
+import qbs.Host
import qbs.TextFile
import "../../../modules/Android/android-utils.js" as AndroidUtils
PathProbe {
// Inputs
- property stringList hostOS: qbs.hostOS
property path sdkPath
environmentPaths: Environment.getEnv("ANDROID_NDK_ROOT")
@@ -45,13 +45,13 @@ PathProbe {
var paths = [];
if (sdkPath)
paths.push(FileInfo.joinPaths(sdkPath, "ndk-bundle"));
- if (qbs.hostOS.contains("windows"))
+ if (Host.os().contains("windows"))
paths.push(FileInfo.joinPaths(Environment.getEnv("LOCALAPPDATA"),
"Android", "sdk", "ndk-bundle"));
- if (qbs.hostOS.contains("macos"))
+ if (Host.os().contains("macos"))
paths.push(FileInfo.joinPaths(Environment.getEnv("HOME"),
"Library", "Android", "sdk", "ndk-bundle"));
- if (qbs.hostOS.contains("linux"))
+ if (Host.os().contains("linux"))
paths.push(FileInfo.joinPaths(Environment.getEnv("HOME"),
"Android", "Sdk", "ndk-bundle"));
return paths;
@@ -83,11 +83,11 @@ PathProbe {
candidatePaths = allPaths;
for (i in allPaths) {
var platforms = [];
- if (hostOS.contains("windows"))
+ if (Host.os().contains("windows"))
platforms.push("windows-x86_64", "windows");
- if (hostOS.contains("darwin"))
+ if (Host.os().contains("darwin"))
platforms.push("darwin-x86_64", "darwin-x86");
- if (hostOS.contains("linux"))
+ if (Host.os().contains("linux"))
platforms.push("linux-x86_64", "linux-x86");
for (j in platforms) {
if (File.exists(FileInfo.joinPaths(allPaths[i], "prebuilt", platforms[j]))) {
diff --git a/share/qbs/imports/qbs/Probes/AndroidSdkProbe.qbs b/share/qbs/imports/qbs/Probes/AndroidSdkProbe.qbs
index 38feecdfa..5b777d3e2 100644
--- a/share/qbs/imports/qbs/Probes/AndroidSdkProbe.qbs
+++ b/share/qbs/imports/qbs/Probes/AndroidSdkProbe.qbs
@@ -31,17 +31,18 @@
import qbs.Environment
import qbs.File
import qbs.FileInfo
+import qbs.Host
import "../../../modules/Android/sdk/utils.js" as SdkUtils
import "../../../modules/Android/android-utils.js" as AndroidUtils
-BinaryProbe {
+PathProbe {
environmentPaths: Environment.getEnv("ANDROID_HOME")
platformSearchPaths: {
- if (qbs.hostOS.contains("windows"))
+ if (Host.os().contains("windows"))
return [FileInfo.joinPaths(Environment.getEnv("LOCALAPPDATA"), "Android", "sdk")];
- if (qbs.hostOS.contains("macos"))
+ if (Host.os().contains("macos"))
return [FileInfo.joinPaths(Environment.getEnv("HOME"), "Library", "Android", "sdk")];
- if (qbs.hostOS.contains("linux"))
+ if (Host.os().contains("linux"))
return [FileInfo.joinPaths(Environment.getEnv("HOME"), "Android", "Sdk")];
}
@@ -53,21 +54,17 @@ BinaryProbe {
property string platform
configure: {
- var suffixes = nameSuffixes || [""];
var i, allPaths = (environmentPaths || []).concat(platformSearchPaths || []);
candidatePaths = allPaths;
for (i in allPaths) {
- for (var j in suffixes) {
- if (File.exists(FileInfo.joinPaths(allPaths[i],
- "tools", "android" + suffixes[j]))) {
- path = allPaths[i];
- buildToolsVersions = SdkUtils.availableBuildToolsVersions(path)
- buildToolsVersion = buildToolsVersions[buildToolsVersions.length - 1];
- platforms = AndroidUtils.availablePlatforms(path)
- platform = platforms[platforms.length - 1];
- found = true;
- return;
- }
+ if (File.exists(FileInfo.joinPaths(allPaths[i], "build-tools"))) {
+ path = allPaths[i];
+ buildToolsVersions = SdkUtils.availableBuildToolsVersions(path)
+ buildToolsVersion = buildToolsVersions[buildToolsVersions.length - 1];
+ platforms = AndroidUtils.availablePlatforms(path)
+ platform = platforms[platforms.length - 1];
+ found = true;
+ return;
}
}
}
diff --git a/share/qbs/imports/qbs/Probes/BinaryProbe.qbs b/share/qbs/imports/qbs/Probes/BinaryProbe.qbs
index 0bb264bd6..52b78df03 100644
--- a/share/qbs/imports/qbs/Probes/BinaryProbe.qbs
+++ b/share/qbs/imports/qbs/Probes/BinaryProbe.qbs
@@ -28,8 +28,10 @@
**
****************************************************************************/
+import qbs.Host
+
PathProbe {
- nameSuffixes: qbs.hostOS.contains("windows") ? [".com", ".exe", ".bat", ".cmd"] : undefined
- platformSearchPaths: hostOS.contains("unix") ? ["/usr/bin", "/usr/local/bin"] : []
+ nameSuffixes: Host.os().contains("windows") ? [".com", ".exe", ".bat", ".cmd"] : undefined
+ platformSearchPaths: Host.os().contains("unix") ? ["/usr/bin", "/usr/local/bin"] : []
platformEnvironmentPaths: [ "PATH" ]
}
diff --git a/share/qbs/imports/qbs/Probes/ClBinaryProbe.qbs b/share/qbs/imports/qbs/Probes/ClBinaryProbe.qbs
new file mode 100644
index 000000000..3b3959017
--- /dev/null
+++ b/share/qbs/imports/qbs/Probes/ClBinaryProbe.qbs
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Ivan Komissarov (abbapoh@gmail.com)
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+import qbs.FileInfo
+import qbs.ModUtils
+import qbs.Utilities
+import "path-probe.js" as PathProbeConfigure
+
+BinaryProbe {
+ // input
+ property string preferredArchitecture
+
+ configure: {
+ var _selectors;
+ var results = PathProbeConfigure.configure(_selectors, names, nameSuffixes, nameFilter,
+ candidateFilter, searchPaths, pathSuffixes,
+ platformSearchPaths, environmentPaths,
+ platformEnvironmentPaths);
+ if (!results.found) {
+ var msvcs = Utilities.installedMSVCs(preferredArchitecture);
+ if (msvcs.length >= 1) {
+ var result = {};
+ result.fileName = "cl.exe";
+ result.path = msvcs[0].binPath;
+ result.filePath = FileInfo.joinPaths(path, fileName);
+ result.candidatePaths = result.filePath;
+ results.found = true;
+ results.files = [result];
+ }
+ }
+
+ found = results.found;
+ allResults = results.files;
+
+ if (allResults.length === 1) {
+ var result = allResults[0];
+ candidatePaths = result.candidatePaths;
+ path = result.path;
+ filePath = result.filePath;
+ fileName = result.fileName;
+ }
+
+ }
+}
diff --git a/share/qbs/imports/qbs/Probes/ClangClBinaryProbe.qbs b/share/qbs/imports/qbs/Probes/ClangClBinaryProbe.qbs
new file mode 100644
index 000000000..8dc01d376
--- /dev/null
+++ b/share/qbs/imports/qbs/Probes/ClangClBinaryProbe.qbs
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Ivan Komissarov (abbapoh@gmail.com)
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+import qbs.FileInfo
+import qbs.ModUtils
+import qbs.Utilities
+import "path-probe.js" as PathProbeConfigure
+
+BinaryProbe {
+ // output
+ property string vcvarsallPath
+
+ configure: {
+ var _selectors;
+ var results = PathProbeConfigure.configure(_selectors, names, nameSuffixes, nameFilter,
+ candidateFilter, searchPaths, pathSuffixes,
+ platformSearchPaths, environmentPaths,
+ platformEnvironmentPaths);
+ var compilerPath;
+ if (results.found)
+ compilerPath = results.files[0].filePath;
+ var compilers = Utilities.installedClangCls(compilerPath);
+ if (compilers.length >= 1) {
+ var result = {};
+ result.fileName = "clang-cl.exe";
+ result.path = compilers[0].toolchainInstallPath;
+ result.filePath = FileInfo.joinPaths(result.path, result.fileName);
+ result.candidatePaths = result.filePath;
+ result.vcvarsallPath = compilers[0].vcvarsallPath;
+ results.found = true;
+ results.files = [result];
+ }
+
+ found = results.found;
+ allResults = results.files;
+
+ if (allResults.length === 1) {
+ var result = allResults[0];
+ candidatePaths = result.candidatePaths;
+ path = result.path;
+ filePath = result.filePath;
+ fileName = result.fileName;
+ vcvarsallPath = result.vcvarsallPath;
+ }
+ }
+}
diff --git a/share/qbs/imports/qbs/Probes/ClangClProbe.qbs b/share/qbs/imports/qbs/Probes/ClangClProbe.qbs
index c7687f0e9..f0d930be5 100644
--- a/share/qbs/imports/qbs/Probes/ClangClProbe.qbs
+++ b/share/qbs/imports/qbs/Probes/ClangClProbe.qbs
@@ -30,6 +30,7 @@
import qbs.File
import qbs.FileInfo
+import qbs.Host
import qbs.ModUtils
import qbs.Utilities
import "../../../modules/cpp/gcc.js" as Gcc
@@ -39,15 +40,15 @@ PathProbe {
property string compilerFilePath
property string vcvarsallFilePath
property stringList enableDefinesByLanguage
- property string architecture
- property string _nullDevice: qbs.nullDevice
- property string _pathListSeparator: qbs.pathListSeparator
+ property string preferredArchitecture
+ property string winSdkVersion
// Outputs
property int versionMajor
property int versionMinor
property int versionPatch
property stringList includePaths
+ property string architecture
property var buildEnv
property var compilerDefinesByLanguage
@@ -57,9 +58,21 @@ PathProbe {
languages = ["c"];
var info = languages.contains("c")
- ? Utilities.clangClCompilerInfo(compilerFilePath, architecture, vcvarsallFilePath, "c") : {};
+ ? Utilities.clangClCompilerInfo(
+ compilerFilePath,
+ preferredArchitecture,
+ vcvarsallFilePath,
+ "c",
+ winSdkVersion)
+ : {};
var infoCpp = languages.contains("cpp")
- ? Utilities.clangClCompilerInfo(compilerFilePath, architecture, vcvarsallFilePath, "cpp") : {};
+ ? Utilities.clangClCompilerInfo(
+ compilerFilePath,
+ preferredArchitecture,
+ vcvarsallFilePath,
+ "cpp",
+ winSdkVersion)
+ : {};
found = (!languages.contains("c") ||
(!!info && !!info.macros && !!info.buildEnvironment))
&& (!languages.contains("cpp") ||
@@ -81,8 +94,9 @@ PathProbe {
var clangPath = FileInfo.joinPaths(FileInfo.path(compilerFilePath), "clang.exe");
var defaultPaths = Gcc.dumpDefaultPaths(buildEnv, clangPath,
- [], _nullDevice,
- _pathListSeparator, "", "");
+ [], Host.nullDevice(),
+ FileInfo.pathListSeparator(), "", "");
includePaths = defaultPaths.includePaths;
+ architecture = ModUtils.guessArchitecture(macros);
}
}
diff --git a/share/qbs/imports/qbs/Probes/ConanfileProbe.qbs b/share/qbs/imports/qbs/Probes/ConanfileProbe.qbs
new file mode 100644
index 000000000..097b1b6f1
--- /dev/null
+++ b/share/qbs/imports/qbs/Probes/ConanfileProbe.qbs
@@ -0,0 +1,145 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Richard Weickelt
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+import qbs.Process
+import qbs.File
+import qbs.FileInfo
+import qbs.TextFile
+import qbs.Utilities
+
+Probe {
+ // Inputs
+ property stringList additionalArguments: []
+ property path conanfilePath
+ property path packageReference
+ property path executable: "conan" + FileInfo.executableSuffix()
+ property stringList generators: ["json"]
+ property var options
+ property var settings
+ property bool verbose: false
+
+ // Output
+ property var dependencies
+ property path generatedFilesPath
+ property var json
+
+ // Internal
+ // Ensure that the probe is re-run automatically whenever conanfile changes
+ // by making a file system property part of the probe's signature.
+ property int _conanfileLastModified: conanfilePath ? File.lastModified(conanfilePath) : 0
+ property path _projectBuildDirectory: project.buildDirectory
+
+ configure: {
+ if (conanfilePath && packageReference)
+ throw("conanfilePath and packageReference must not be defined at the same time.");
+
+ if (!conanfilePath && !packageReference)
+ throw("Either conanfilePath or packageReference must be defined.");
+
+ var reference = packageReference || FileInfo.cleanPath(conanfilePath);
+ console.info("Probing '" + reference + "'. This might take a while...");
+ if (conanfilePath && !File.exists(reference))
+ throw("The conanfile '" + reference + "' does not exist.");
+
+ var args = [
+ "install", reference,
+ ];
+
+ if (options) {
+ if (typeof options !== "object")
+ throw("The property 'options' must be an object.");
+ Object.keys(options).forEach(function(key,index) {
+ args.push("-o");
+ args.push(key + "=" + options[key]);
+ });
+ }
+
+ if (settings) {
+ if (typeof settings !== "object")
+ throw("The property 'settings' must be an object.");
+ Object.keys(settings).forEach(function(key,index) {
+ args.push("-s");
+ args.push(key + "=" + settings[key]);
+ });
+ }
+
+ if (!generators.contains("json"))
+ generators.push("json");
+
+ for (var i = 0; i < generators.length; i++)
+ args = args.concat(["-g", generators[i]]);
+
+ for (var i = 0; i < additionalArguments.length; i++)
+ args.push(additionalArguments[i]);
+
+ generatedFilesPath = FileInfo.cleanPath(_projectBuildDirectory +
+ "/genconan/" +
+ Utilities.getHash(args.join()));
+
+ args = args.concat(["-if", generatedFilesPath]);
+ var p = new Process();
+ p.start(executable, args);
+ while (!p.waitForFinished(500)) {
+ const output = p.readStdOut();
+ if (verbose && output) {
+ console.info(output);
+ }
+ }
+ while (!p.atEnd()) {
+ const output = p.readStdOut();
+ if (verbose && output) {
+ console.info(output);
+ }
+ }
+ if (p.exitCode()) {
+ const errorOutput = p.readStdErr();
+ p.close();
+ throw errorOutput;
+ }
+ p.close();
+
+ if (generators.contains("json")) {
+ if (!File.exists(generatedFilesPath + "/conanbuildinfo.json"))
+ throw("No conanbuildinfo.json has been generated.");
+
+ var jsonFile = new TextFile(generatedFilesPath + "/conanbuildinfo.json", TextFile.ReadOnly);
+ json = JSON.parse(jsonFile.readAll());
+ jsonFile.close();
+
+ dependencies = {};
+ for (var i = 0; i < json.dependencies.length; ++i) {
+ var dep = json.dependencies[i];
+ dependencies[dep.name] = dep;
+ }
+ }
+
+ found = true;
+ }
+}
diff --git a/share/qbs/imports/qbs/Probes/CosmicProbe.qbs b/share/qbs/imports/qbs/Probes/CosmicProbe.qbs
new file mode 100644
index 000000000..7de781e6e
--- /dev/null
+++ b/share/qbs/imports/qbs/Probes/CosmicProbe.qbs
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+import qbs.File
+import "../../../modules/cpp/cosmic.js" as COSMIC
+
+PathProbe {
+ // Inputs
+ property string compilerFilePath
+ property stringList enableDefinesByLanguage
+
+ // Outputs
+ property string architecture
+ property string endianness
+ property int versionMajor
+ property int versionMinor
+ property int versionPatch
+ property stringList includePaths
+ property var compilerDefinesByLanguage
+
+ configure: {
+ compilerDefinesByLanguage = {};
+
+ if (!File.exists(compilerFilePath)) {
+ found = false;
+ return;
+ }
+
+ var languages = enableDefinesByLanguage;
+ if (!languages || languages.length === 0)
+ languages = ["c"];
+
+ // COSMIC compiler support only the C-language.
+ if (!languages.contains("c")) {
+ found = false;
+ return;
+ }
+
+ var macros = COSMIC.dumpMacros(compilerFilePath);
+ if (!macros) {
+ found = false;
+ return;
+ }
+
+ compilerDefinesByLanguage["c"] = macros;
+
+ architecture = COSMIC.guessArchitecture(compilerFilePath);
+ endianness = COSMIC.guessEndianness(architecture);
+ var defaultPaths = COSMIC.dumpDefaultPaths(compilerFilePath, architecture);
+ includePaths = defaultPaths.includePaths;
+
+ var version = COSMIC.dumpVersion(compilerFilePath);
+ if (version) {
+ versionMajor = version.major;
+ versionMinor = version.minor;
+ versionPatch = version.patch;
+ found = !!architecture && !!endianness;
+ }
+ }
+}
diff --git a/share/qbs/imports/qbs/Probes/DmcProbe.qbs b/share/qbs/imports/qbs/Probes/DmcProbe.qbs
new file mode 100644
index 000000000..6a8723a3b
--- /dev/null
+++ b/share/qbs/imports/qbs/Probes/DmcProbe.qbs
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+import qbs.File
+import qbs.ModUtils
+import "../../../modules/cpp/dmc.js" as DMC
+
+PathProbe {
+ // Inputs
+ property string compilerFilePath
+ property stringList enableDefinesByLanguage
+
+ property string _targetPlatform
+ property string _targetArchitecture
+ property string _targetExtender // Only for DOS 16/32 bit.
+
+ // Outputs
+ property string architecture
+ property string targetPlatform
+ property int versionMajor
+ property int versionMinor
+ property int versionPatch
+ property stringList includePaths
+ property var compilerDefinesByLanguage
+
+ configure: {
+ compilerDefinesByLanguage = {};
+
+ if (!File.exists(compilerFilePath)) {
+ found = false;
+ return;
+ }
+
+ var languages = enableDefinesByLanguage;
+ if (!languages || languages.length === 0)
+ languages = ["c"];
+
+ var defaultPathsByLanguage = {};
+ for (var i = 0; i < languages.length; ++i) {
+ var tag = languages[i];
+ compilerDefinesByLanguage[tag] = DMC.dumpMacros(
+ compilerFilePath,
+ _targetPlatform,
+ _targetArchitecture,
+ _targetExtender,
+ tag);
+ var paths = DMC.dumpDefaultPaths(compilerFilePath, tag);
+ defaultPathsByLanguage[tag] = paths;
+ }
+
+ var macros = compilerDefinesByLanguage["c"]
+ || compilerDefinesByLanguage["cpp"];
+
+ architecture = ModUtils.guessArchitecture(macros);
+ targetPlatform = ModUtils.guessTargetPlatform(macros);
+
+ var defaultPaths = defaultPathsByLanguage["cpp"]
+ || defaultPathsByLanguage["c"];
+
+ includePaths = defaultPaths.includePaths;
+
+ var version = DMC.guessVersion(macros);
+ if (version) {
+ versionMajor = version.major;
+ versionMinor = version.minor;
+ versionPatch = version.patch;
+ found = !!architecture;
+ }
+ }
+}
diff --git a/share/qbs/imports/qbs/Probes/FrameworkProbe.qbs b/share/qbs/imports/qbs/Probes/FrameworkProbe.qbs
index e0fe73b40..c3d98a49f 100644
--- a/share/qbs/imports/qbs/Probes/FrameworkProbe.qbs
+++ b/share/qbs/imports/qbs/Probes/FrameworkProbe.qbs
@@ -35,10 +35,5 @@ PathProbe {
"/Library/Frameworks",
"/System/Library/Frameworks"
])
-
- nameFilter: {
- return function(name) {
- return name + ".framework";
- }
- }
+ nameSuffixes: ".framework"
}
diff --git a/share/qbs/imports/qbs/Probes/GccBinaryProbe.qbs b/share/qbs/imports/qbs/Probes/GccBinaryProbe.qbs
index 693fb6a01..0872e6cc0 100644
--- a/share/qbs/imports/qbs/Probes/GccBinaryProbe.qbs
+++ b/share/qbs/imports/qbs/Probes/GccBinaryProbe.qbs
@@ -1,8 +1,10 @@
import qbs.Environment
import qbs.FileInfo
+import qbs.Host
import "path-probe.js" as PathProbeConfigure
BinaryProbe {
+ nameSuffixes: undefined // _compilerName already contains ".exe" suffix on Windows
// Inputs
property string _compilerName
property string _toolchainPrefix
@@ -12,7 +14,7 @@ BinaryProbe {
platformSearchPaths: {
var paths = base;
- if (qbs.targetOS.contains("windows") && qbs.hostOS.contains("windows"))
+ if (qbs.targetOS.contains("windows") && Host.os().contains("windows"))
paths.push(FileInfo.joinPaths(
Environment.getEnv("SystemDrive"), "MinGW", "bin"));
return paths;
@@ -48,20 +50,29 @@ BinaryProbe {
configure: {
var selectors;
- var _results = PathProbeConfigure.configure(
+ var results = PathProbeConfigure.configure(
selectors, names, nameSuffixes, nameFilter, candidateFilter, searchPaths,
- pathSuffixes, platformSearchPaths, environmentPaths, platformEnvironmentPaths,
- pathListSeparator);
- found = _results.found;
- var resultFile = _results.files[0];
- candidatePaths = resultFile.candidatePaths;
- path = resultFile.path;
- filePath = resultFile.filePath;
- fileName = resultFile.fileName;
- (nameSuffixes || [""]).forEach(function(suffix) {
- var end = _compilerName + suffix;
- if (fileName.endsWith(end))
- tcPrefix = fileName.slice(0, -end.length);
- });
+ pathSuffixes, platformSearchPaths, environmentPaths, platformEnvironmentPaths);
+
+ found = results.found;
+ if (!found)
+ return;
+
+ var resultsMapper = function(result) {
+ (nameSuffixes || [""]).forEach(function(suffix) {
+ var end = _compilerName + suffix;
+ if (result.fileName.endsWith(end))
+ result.tcPrefix = result.fileName.slice(0, -end.length);
+ });
+ return result;
+ };
+ results.files = results.files.map(resultsMapper);
+ allResults = results.files;
+ var result = results.files[0];
+ candidatePaths = result.candidatePaths;
+ path = result.path;
+ filePath = result.filePath;
+ fileName = result.fileName;
+ tcPrefix = result.tcPrefix;
}
}
diff --git a/share/qbs/imports/qbs/Probes/GccProbe.qbs b/share/qbs/imports/qbs/Probes/GccProbe.qbs
index 9106ff27b..5c6dc1936 100644
--- a/share/qbs/imports/qbs/Probes/GccProbe.qbs
+++ b/share/qbs/imports/qbs/Probes/GccProbe.qbs
@@ -29,6 +29,8 @@
****************************************************************************/
import qbs.File
+import qbs.FileInfo
+import qbs.Host
import qbs.ModUtils
import "../../../modules/cpp/gcc.js" as Gcc
@@ -39,8 +41,6 @@ PathProbe {
property stringList flags: []
property var environment
- property string _nullDevice: qbs.nullDevice
- property string _pathListSeparator: qbs.pathListSeparator
property string _sysroot: qbs.sysroot
property stringList _targetOS: qbs.targetOS
@@ -63,7 +63,8 @@ PathProbe {
if (fp && File.exists(fp)) {
try {
compilerDefinesByLanguage[languages[i]] = Gcc.dumpMacros(environment, fp,
- flags, _nullDevice,
+ flags,
+ Host.nullDevice(),
languages[i]);
} catch (e) {
// Only throw errors when determining the compiler defines for the C language;
@@ -84,8 +85,8 @@ PathProbe {
|| compilerDefinesByLanguage["objcpp"];
var defaultPaths = Gcc.dumpDefaultPaths(environment, compilerFilePathByLanguage["cpp"] ||
compilerFilePathByLanguage["c"],
- flags, _nullDevice,
- _pathListSeparator, _sysroot, _targetOS);
+ flags, Host.nullDevice(),
+ FileInfo.pathListSeparator(), _sysroot, _targetOS);
found = !!macros && !!defaultPaths;
includePaths = defaultPaths.includePaths;
diff --git a/share/qbs/imports/qbs/Probes/GccVersionProbe.qbs b/share/qbs/imports/qbs/Probes/GccVersionProbe.qbs
index 528719e5b..497835479 100644
--- a/share/qbs/imports/qbs/Probes/GccVersionProbe.qbs
+++ b/share/qbs/imports/qbs/Probes/GccVersionProbe.qbs
@@ -29,6 +29,7 @@
****************************************************************************/
import qbs.File
+import qbs.Host
import "../../../modules/cpp/gcc.js" as Gcc
PathProbe {
@@ -36,7 +37,6 @@ PathProbe {
property string compilerFilePath
property var environment
- property string _nullDevice: qbs.nullDevice
property stringList _toolchain: qbs.toolchain
// Outputs
@@ -50,7 +50,7 @@ PathProbe {
return;
}
- var macros = Gcc.dumpMacros(environment, compilerFilePath, undefined, _nullDevice);
+ var macros = Gcc.dumpMacros(environment, compilerFilePath, undefined, Host.nullDevice());
if (_toolchain.contains("clang")) {
versionMajor = parseInt(macros["__clang_major__"], 10);
diff --git a/share/qbs/imports/qbs/Probes/IarProbe.qbs b/share/qbs/imports/qbs/Probes/IarProbe.qbs
index d261e9065..a0008be47 100644
--- a/share/qbs/imports/qbs/Probes/IarProbe.qbs
+++ b/share/qbs/imports/qbs/Probes/IarProbe.qbs
@@ -33,19 +33,17 @@ import "../../../modules/cpp/iar.js" as IAR
PathProbe {
// Inputs
- property string compilerFilePath;
- property stringList enableDefinesByLanguage;
-
- property string _nullDevice: qbs.nullDevice
+ property string compilerFilePath
+ property stringList enableDefinesByLanguage
// Outputs
- property string architecture;
- property string endianness;
- property int versionMajor;
- property int versionMinor;
- property int versionPatch;
- property stringList includePaths;
- property var compilerDefinesByLanguage;
+ property string architecture
+ property string endianness
+ property int versionMajor
+ property int versionMinor
+ property int versionPatch
+ property stringList includePaths
+ property var compilerDefinesByLanguage
configure: {
compilerDefinesByLanguage = {};
@@ -59,10 +57,13 @@ PathProbe {
if (!languages || languages.length === 0)
languages = ["c"];
+ var defaultPathsByLanguage = {};
for (var i = 0; i < languages.length; ++i) {
var tag = languages[i];
compilerDefinesByLanguage[tag] = IAR.dumpMacros(
compilerFilePath, tag);
+ var paths = IAR.dumpDefaultPaths(compilerFilePath, tag);
+ defaultPathsByLanguage[tag] = paths;
}
var macros = compilerDefinesByLanguage["c"]
@@ -71,10 +72,8 @@ PathProbe {
architecture = IAR.guessArchitecture(macros);
endianness = IAR.guessEndianness(macros);
- // FIXME: Do we need dump the default paths for both C
- // and C++ languages?
- var defaultPaths = IAR.dumpDefaultPaths(
- compilerFilePath, languages[0]);
+ var defaultPaths = defaultPathsByLanguage["cpp"]
+ || defaultPathsByLanguage["c"];
includePaths = defaultPaths.includePaths;
@@ -83,7 +82,7 @@ PathProbe {
versionMajor = version.major;
versionMinor = version.minor;
versionPatch = version.patch;
- found = version && architecture && endianness;
+ found = !!architecture && !!endianness;
}
}
}
diff --git a/share/qbs/imports/qbs/Probes/IncludeProbe.qbs b/share/qbs/imports/qbs/Probes/IncludeProbe.qbs
index 3c1059e64..6201cbc55 100644
--- a/share/qbs/imports/qbs/Probes/IncludeProbe.qbs
+++ b/share/qbs/imports/qbs/Probes/IncludeProbe.qbs
@@ -32,6 +32,8 @@ PathProbe {
platformSearchPaths: qbs.targetOS.contains("unix") ? [
"/usr/include",
"/usr/local/include",
+ "/include",
+ "/app/include",
] : []
platformEnvironmentPaths: {
if (qbs.toolchain.contains('msvc'))
diff --git a/share/qbs/imports/qbs/Probes/InnoSetupProbe.qbs b/share/qbs/imports/qbs/Probes/InnoSetupProbe.qbs
index 2c06a6a0b..87475cb53 100644
--- a/share/qbs/imports/qbs/Probes/InnoSetupProbe.qbs
+++ b/share/qbs/imports/qbs/Probes/InnoSetupProbe.qbs
@@ -35,18 +35,25 @@ PathProbe {
property var version
configure: {
- var keySuffix = "Microsoft\\Windows\\CurrentVersion\\Uninstall\\Inno Setup 5_is1";
var keys = [
- "HKEY_LOCAL_MACHINE\\SOFTWARE\\" + keySuffix,
- "HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\" + keySuffix
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\",
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\"
];
- for (var i in keys) {
- var v = Utilities.getNativeSetting(keys[i], "DisplayVersion");
- if (v) {
- path = Utilities.getNativeSetting(keys[i], "InstallLocation");
- version = v;
- found = path && version;
- return;
+ var keySuffixes = [
+ "Microsoft\\Windows\\CurrentVersion\\Uninstall\\Inno Setup 5_is1",
+ "Microsoft\\Windows\\CurrentVersion\\Uninstall\\Inno Setup 6_is1"
+ ];
+ for (var i = 0; i < keys.length; ++i) {
+ for (var j = 0; j < keySuffixes.length; ++j) {
+ var key = keys[i] + keySuffixes[j];
+
+ var v = Utilities.getNativeSetting(key, "DisplayVersion");
+ if (v) {
+ path = Utilities.getNativeSetting(key, "InstallLocation");
+ version = v;
+ found = path && version;
+ return;
+ }
}
}
}
diff --git a/share/qbs/imports/qbs/Probes/JdkProbe.qbs b/share/qbs/imports/qbs/Probes/JdkProbe.qbs
index 1f414b0fa..efb5a5336 100644
--- a/share/qbs/imports/qbs/Probes/JdkProbe.qbs
+++ b/share/qbs/imports/qbs/Probes/JdkProbe.qbs
@@ -30,14 +30,14 @@
****************************************************************************/
import qbs.Environment
+import qbs.Host
import "../../../modules/java/utils.js" as JavaUtils
PathProbe {
// Inputs
- property stringList hostOS: qbs.hostOS
property string architecture: !_androidCrossCompiling ? qbs.architecture : undefined
property bool _androidCrossCompiling: qbs.targetOS.contains("android")
- && !qbs.hostOS.contains("android")
+ && !Host.os().contains("android")
environmentPaths: Environment.getEnv("JAVA_HOME")
platformSearchPaths: [
@@ -47,7 +47,8 @@ PathProbe {
]
configure: {
- path = JavaUtils.findJdkPath(hostOS, architecture, environmentPaths, platformSearchPaths);
+ path = JavaUtils.findJdkPath(Host.os(), architecture, environmentPaths,
+ platformSearchPaths);
found = !!path;
}
}
diff --git a/share/qbs/imports/qbs/Probes/KeilProbe.qbs b/share/qbs/imports/qbs/Probes/KeilProbe.qbs
index 34afecb64..b123584ad 100644
--- a/share/qbs/imports/qbs/Probes/KeilProbe.qbs
+++ b/share/qbs/imports/qbs/Probes/KeilProbe.qbs
@@ -29,23 +29,22 @@
****************************************************************************/
import qbs.File
+import qbs.Host
import "../../../modules/cpp/keil.js" as KEIL
PathProbe {
// Inputs
- property string compilerFilePath;
- property stringList enableDefinesByLanguage;
-
- property string _nullDevice: qbs.nullDevice
+ property string compilerFilePath
+ property stringList enableDefinesByLanguage
// Outputs
- property string architecture;
- property string endianness;
- property int versionMajor;
- property int versionMinor;
- property int versionPatch;
- property stringList includePaths;
- property var compilerDefinesByLanguage;
+ property string architecture
+ property string endianness
+ property int versionMajor
+ property int versionMinor
+ property int versionPatch
+ property stringList includePaths
+ property var compilerDefinesByLanguage
configure: {
compilerDefinesByLanguage = {};
@@ -62,7 +61,7 @@ PathProbe {
for (var i = 0; i < languages.length; ++i) {
var tag = languages[i];
compilerDefinesByLanguage[tag] = KEIL.dumpMacros(
- compilerFilePath, tag, _nullDevice);
+ compilerFilePath, tag, Host.nullDevice());
}
var macros = compilerDefinesByLanguage["c"]
@@ -72,7 +71,7 @@ PathProbe {
endianness = KEIL.guessEndianness(macros);
var defaultPaths = KEIL.dumpDefaultPaths(
- compilerFilePath, architecture);
+ compilerFilePath, Host.nullDevice());
includePaths = defaultPaths.includePaths;
@@ -81,7 +80,7 @@ PathProbe {
versionMajor = version.major;
versionMinor = version.minor;
versionPatch = version.patch;
- found = version.found && architecture && endianness;
+ found = !!architecture && !!endianness;
}
}
}
diff --git a/share/qbs/imports/qbs/Probes/LibraryProbe.qbs b/share/qbs/imports/qbs/Probes/LibraryProbe.qbs
index 26787d1b4..d67a81372 100644
--- a/share/qbs/imports/qbs/Probes/LibraryProbe.qbs
+++ b/share/qbs/imports/qbs/Probes/LibraryProbe.qbs
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2018 Ivan Komissarov.
+** Copyright (C) 2018 Ivan Komissarov (abbapoh@gmail.com)
** Contact: http://www.qt.io/licensing
**
** This file is part of Qbs.
@@ -28,29 +28,40 @@
**
****************************************************************************/
+import qbs.PathTools
+
PathProbe {
- nameSuffixes: {
- if (qbs.targetOS.contains("windows"))
- return [".lib"];
- if (qbs.targetOS.contains("macos"))
- return [".dylib", ".a"];
- return [".so", ".a"];
- }
- platformSearchPaths: qbs.targetOS.contains("unix") ? [
- "/usr/lib",
- "/usr/local/lib",
- ] : []
- nameFilter: {
+ property string endianness
+ nameSuffixes: PathTools.librarySuffixes(qbs.targetOS, ["shared", "static"], true)
+ platformSearchPaths: {
+ var result = [];
if (qbs.targetOS.contains("unix")) {
- return function(name) {
- return "lib" + name;
- }
- } else {
- return function(name) {
- return name;
+ if (qbs.targetOS.contains("linux") && qbs.architecture) {
+ if (qbs.architecture === "armv7")
+ result = ["/usr/lib/arm-linux-gnueabihf"]
+ else if (qbs.architecture === "arm64")
+ result = ["/usr/lib/aarch64-linux-gnu"]
+ else if (qbs.architecture === "mips" && endianness === "big")
+ result = ["/usr/lib/mips-linux-gnu"]
+ else if (qbs.architecture === "mips" && endianness === "little")
+ result = ["/usr/lib/mipsel-linux-gnu"]
+ else if (qbs.architecture === "mips64")
+ result = ["/usr/lib/mips64el-linux-gnuabi64"]
+ else if (qbs.architecture === "ppc")
+ result = ["/usr/lib/powerpc-linux-gnu"]
+ else if (qbs.architecture === "ppc64")
+ result = ["/usr/lib/powerpc64le-linux-gnu"]
+ else if (qbs.architecture === "x86_64")
+ result = ["/usr/lib64", "/usr/lib/x86_64-linux-gnu"]
+ else if (qbs.architecture === "x86")
+ result = ["/usr/lib32", "/usr/lib/i386-linux-gnu"]
}
+ result = result.concat(["/usr/lib", "/usr/local/lib", "/lib", "/app/lib"]);
}
+
+ return result;
}
+ nameFilter: PathTools.libraryNameFilter(qbs.targetOS)
platformEnvironmentPaths: {
if (qbs.targetOS.contains("windows"))
return [ "PATH" ];
diff --git a/share/qbs/imports/qbs/Probes/MsvcProbe.qbs b/share/qbs/imports/qbs/Probes/MsvcProbe.qbs
index 2d5faecdd..d3624e010 100644
--- a/share/qbs/imports/qbs/Probes/MsvcProbe.qbs
+++ b/share/qbs/imports/qbs/Probes/MsvcProbe.qbs
@@ -38,6 +38,7 @@ PathProbe {
property string compilerFilePath
property stringList enableDefinesByLanguage
property string preferredArchitecture
+ property string winSdkVersion
// Outputs
property string architecture
@@ -54,9 +55,9 @@ PathProbe {
languages = ["c"];
var info = languages.contains("c")
- ? Utilities.msvcCompilerInfo(compilerFilePath, "c") : {};
+ ? Utilities.msvcCompilerInfo(compilerFilePath, "c", winSdkVersion) : {};
var infoCpp = languages.contains("cpp")
- ? Utilities.msvcCompilerInfo(compilerFilePath, "cpp") : {};
+ ? Utilities.msvcCompilerInfo(compilerFilePath, "cpp", winSdkVersion) : {};
found = (!languages.contains("c") ||
(!!info && !!info.macros && !!info.buildEnvironment))
&& (!languages.contains("cpp") ||
diff --git a/share/qbs/imports/qbs/Probes/NodeJsProbe.qbs b/share/qbs/imports/qbs/Probes/NodeJsProbe.qbs
index b0162c715..520e57f56 100644
--- a/share/qbs/imports/qbs/Probes/NodeJsProbe.qbs
+++ b/share/qbs/imports/qbs/Probes/NodeJsProbe.qbs
@@ -30,12 +30,13 @@
import qbs.Environment
import qbs.FileInfo
+import qbs.Host
BinaryProbe {
names: ["node", "nodejs"]
platformSearchPaths: {
var paths = base;
- if (qbs.hostOS.contains("windows")) {
+ if (Host.os().contains("windows")) {
var env32 = Environment.getEnv("PROGRAMFILES(X86)");
var env64 = Environment.getEnv("PROGRAMFILES");
if (env64 === env32 && env64.endsWith(" (x86)"))
diff --git a/share/qbs/imports/qbs/Probes/NpmProbe.qbs b/share/qbs/imports/qbs/Probes/NpmProbe.qbs
index f6a99e826..08490065a 100644
--- a/share/qbs/imports/qbs/Probes/NpmProbe.qbs
+++ b/share/qbs/imports/qbs/Probes/NpmProbe.qbs
@@ -28,6 +28,8 @@
**
****************************************************************************/
+import qbs.FileInfo
+import qbs.Host
import qbs.ModUtils
import "path-probe.js" as PathProbeConfigure
import "../../../modules/nodejs/nodejs.js" as NodeJs
@@ -50,25 +52,30 @@ NodeJsProbe {
var selectors;
var results = PathProbeConfigure.configure(
selectors, names, nameSuffixes, nameFilter, candidateFilter, searchPaths,
- pathSuffixes, platformSearchPaths, environmentPaths, platformEnvironmentPaths,
- pathListSeparator);
+ pathSuffixes, platformSearchPaths, environmentPaths, platformEnvironmentPaths);
- var v = new ModUtils.EnvironmentVariable("PATH", pathListSeparator,
- hostOS.contains("windows"));
+ var v = new ModUtils.EnvironmentVariable("PATH", FileInfo.pathListSeparator(),
+ Host.os().contains("windows"));
v.prepend(interpreterPath);
- var result = results.files[0];
- result.npmBin = results.found
- ? NodeJs.findLocation(result.filePath, "bin", v.value)
- : undefined;
- result.npmRoot = results.found
- ? NodeJs.findLocation(result.filePath, "root", v.value)
- : undefined;
- result.npmPrefix = results.found
- ? NodeJs.findLocation(result.filePath, "prefix", v.value)
- : undefined;
+ var resultsMapper = function(result) {
+ result.npmBin = result.found
+ ? NodeJs.findLocation(result.filePath, "bin", v.value)
+ : undefined;
+ result.npmRoot = result.found
+ ? NodeJs.findLocation(result.filePath, "root", v.value)
+ : undefined;
+ result.npmPrefix = result.found
+ ? NodeJs.findLocation(result.filePath, "prefix", v.value)
+ : undefined;
+ return result;
+ };
+ results.files = results.files.map(resultsMapper);
found = results.found;
+ allResults = results.files;
+
+ var result = results.files[0];
candidatePaths = result.candidatePaths;
path = result.path;
filePath = result.filePath;
diff --git a/share/qbs/imports/qbs/Probes/PathProbe.qbs b/share/qbs/imports/qbs/Probes/PathProbe.qbs
index d0edea682..dc3b32ab7 100644
--- a/share/qbs/imports/qbs/Probes/PathProbe.qbs
+++ b/share/qbs/imports/qbs/Probes/PathProbe.qbs
@@ -29,6 +29,7 @@
****************************************************************************/
import "path-probe.js" as PathProbeConfigure
+import qbs.Host
import qbs.ModUtils
Probe {
@@ -38,15 +39,11 @@ Probe {
property var nameFilter
property var candidateFilter
property varList selectors
- property pathList pathPrefixes
property pathList searchPaths
property stringList pathSuffixes
- property pathList platformSearchPaths: hostOS.contains("unix") ? ['/usr', '/usr/local'] : []
- property pathList platformPaths
+ property pathList platformSearchPaths: Host.os().contains("unix") ? ['/usr', '/usr/local'] : []
property stringList environmentPaths
property stringList platformEnvironmentPaths
- property stringList hostOS: qbs.hostOS
- property string pathListSeparator: qbs.pathListSeparator
// Output
property stringList candidatePaths
@@ -57,23 +54,19 @@ Probe {
property varList allResults
configure: {
- if (pathPrefixes)
- console.warn("PathProbe.pathPrefixes is deprecated, use searchPaths instead");
- if (platformPaths)
- console.warn("PathProbe.platformPaths is deprecated, use platformSearchPaths instead");
- var _searchPaths = ModUtils.concatAll(pathPrefixes, searchPaths);
- var _platformSearchPaths = ModUtils.concatAll(platformPaths, platformSearchPaths);
var results = PathProbeConfigure.configure(selectors, names, nameSuffixes, nameFilter,
- candidateFilter, _searchPaths, pathSuffixes,
- _platformSearchPaths, environmentPaths,
- platformEnvironmentPaths, pathListSeparator);
+ candidateFilter, searchPaths, pathSuffixes,
+ platformSearchPaths, environmentPaths,
+ platformEnvironmentPaths);
found = results.found;
allResults = results.files;
- var result = allResults[0];
- candidatePaths = result.candidatePaths;
- path = result.path;
- filePath = result.filePath;
- fileName = result.fileName;
+ if (allResults.length === 1) {
+ var result = allResults[0];
+ candidatePaths = result.candidatePaths;
+ path = result.path;
+ filePath = result.filePath;
+ fileName = result.fileName;
+ }
}
}
diff --git a/share/qbs/imports/qbs/Probes/PkgConfigProbe.qbs b/share/qbs/imports/qbs/Probes/PkgConfigProbe.qbs
index b295c7441..0fe81c3cc 100644
--- a/share/qbs/imports/qbs/Probes/PkgConfigProbe.qbs
+++ b/share/qbs/imports/qbs/Probes/PkgConfigProbe.qbs
@@ -28,6 +28,7 @@
**
****************************************************************************/
+import qbs.Host
import qbs.Process
import qbs.FileInfo
@@ -42,7 +43,6 @@ Probe {
property string maxVersion
property bool forStaticBuild: false
property stringList libDirs // Full, non-sysrooted paths, mirroring the environment variable
- property string pathListSeparator: qbs.pathListSeparator
// Output
property stringList cflags // Unmodified --cflags output
@@ -60,6 +60,7 @@ Probe {
if (!packageNames || packageNames.length === 0)
throw 'PkgConfigProbe.packageNames must be specified.';
var p = new Process();
+ var stdout;
try {
var libDirsToSet = libDirs;
if (sysroot) {
@@ -72,7 +73,7 @@ Probe {
}
}
if (libDirsToSet)
- p.setEnv("PKG_CONFIG_LIBDIR", libDirsToSet.join(pathListSeparator));
+ p.setEnv("PKG_CONFIG_LIBDIR", libDirsToSet.join(FileInfo.pathListSeparator()));
var versionArgs = [];
if (minVersion !== undefined)
versionArgs.push("--atleast-version=" + minVersion);
@@ -84,16 +85,22 @@ Probe {
&& p.exec(executable, versionArgs.concat(packageNames)) !== 0) {
return;
}
+
+ // protobuf is reserved as qbs module name, which depends on the protobuflib module
+ packageNames = packageNames.map(function(name) {
+ return name === "protobuflib" ? "protobuf" : name;
+ });
+
var args = packageNames;
if (p.exec(executable, args.concat([ '--cflags' ])) === 0) {
- cflags = p.readStdOut().trim();
- cflags = cflags ? cflags.split(/\s/) : [];
+ stdout = p.readStdOut().trim();
+ cflags = stdout ? stdout.split(/\s/): [];
var libsArgs = args.concat("--libs");
if (forStaticBuild)
libsArgs.push("--static");
if (p.exec(executable, libsArgs) === 0) {
- libs = p.readStdOut().trim();
- libs = libs ? libs.split(/\s/) : [];
+ stdout = p.readStdOut().trim();
+ libs = stdout ? stdout.split(/\s/): [];
if (p.exec(executable, [packageNames[0]].concat([ '--modversion' ])) === 0) {
modversion = p.readStdOut().trim();
found = true;
diff --git a/share/qbs/imports/qbs/Probes/QbsPkgConfigProbe.qbs b/share/qbs/imports/qbs/Probes/QbsPkgConfigProbe.qbs
new file mode 100644
index 000000000..5acec6bc0
--- /dev/null
+++ b/share/qbs/imports/qbs/Probes/QbsPkgConfigProbe.qbs
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 Ivan Komissarov (abbapoh@gmail.com)
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+import "qbs-pkg-config-probe.js" as PkgConfigProbeConfigure
+
+Probe {
+ // Inputs
+
+ property string _executableFilePath
+ property stringList _extraPaths
+ property stringList _libDirs
+ property bool _staticMode: false
+ property bool _definePrefix: false
+
+ property path _sysroot
+
+ // Output
+ property var packages
+ property var packagesByModuleName
+ property var brokenPackages
+ property stringList qmakePaths
+
+ configure: {
+ var result = PkgConfigProbeConfigure.configure(
+ _executableFilePath,
+ _extraPaths,
+ _libDirs,
+ _staticMode,
+ _definePrefix,
+ _sysroot);
+ packages = result.packages;
+ packagesByModuleName = result.packagesByModuleName;
+ brokenPackages = result.brokenPackages;
+ qmakePaths = result.qmakePaths;
+ found = true;
+ }
+}
diff --git a/share/qbs/imports/qbs/Probes/QmakeProbe.qbs b/share/qbs/imports/qbs/Probes/QmakeProbe.qbs
new file mode 100644
index 000000000..c50c6c851
--- /dev/null
+++ b/share/qbs/imports/qbs/Probes/QmakeProbe.qbs
@@ -0,0 +1,41 @@
+
+/****************************************************************************
+**
+** Copyright (C) 2023 Ivan Komissarov (abbapoh@gmail.com)
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+import "qmake-probe.js" as QmakeProbeConfigure
+
+Probe {
+ property stringList qmakePaths
+ property varList qtInfos
+
+ configure: {
+ qtInfos = QmakeProbeConfigure.configure(qmakePaths);
+ }
+}
diff --git a/share/qbs/imports/qbs/Probes/SdccProbe.qbs b/share/qbs/imports/qbs/Probes/SdccProbe.qbs
index 3595bb158..ae616fa27 100644
--- a/share/qbs/imports/qbs/Probes/SdccProbe.qbs
+++ b/share/qbs/imports/qbs/Probes/SdccProbe.qbs
@@ -33,17 +33,18 @@ import "../../../modules/cpp/sdcc.js" as SDCC
PathProbe {
// Inputs
- property string compilerFilePath;
- property string preferredArchitecture;
+ property string compilerFilePath
+ property stringList enableDefinesByLanguage
+ property string preferredArchitecture
// Outputs
- property string architecture;
- property string endianness;
- property int versionMajor;
- property int versionMinor;
- property int versionPatch;
- property stringList includePaths;
- property var compilerDefinesByLanguage;
+ property string architecture
+ property string endianness
+ property int versionMajor
+ property int versionMinor
+ property int versionPatch
+ property stringList includePaths
+ property var compilerDefinesByLanguage
configure: {
compilerDefinesByLanguage = {};
@@ -53,9 +54,22 @@ PathProbe {
return;
}
+ var languages = enableDefinesByLanguage;
+ if (!languages || languages.length === 0)
+ languages = ["c"];
+
+ // SDCC compiler support only the C-language.
+ if (!languages.contains("c")) {
+ found = false;
+ return;
+ }
+
var macros = SDCC.dumpMacros(compilerFilePath, preferredArchitecture);
+ if (!macros) {
+ found = false;
+ return;
+ }
- // SDCC it is only the C language compiler.
compilerDefinesByLanguage["c"] = macros;
architecture = SDCC.guessArchitecture(macros);
@@ -65,9 +79,11 @@ PathProbe {
includePaths = defaultPaths.includePaths;
var version = SDCC.guessVersion(macros);
- versionMajor = version.major;
- versionMinor = version.minor;
- versionPatch = version.patch;
- found = version.found;
+ if (version) {
+ versionMajor = version.major;
+ versionMinor = version.minor;
+ versionPatch = version.patch;
+ found = !!architecture && !!endianness;
+ }
}
}
diff --git a/share/qbs/imports/qbs/Probes/TypeScriptProbe.qbs b/share/qbs/imports/qbs/Probes/TypeScriptProbe.qbs
index a35e555cc..f494d6012 100644
--- a/share/qbs/imports/qbs/Probes/TypeScriptProbe.qbs
+++ b/share/qbs/imports/qbs/Probes/TypeScriptProbe.qbs
@@ -30,6 +30,7 @@
import qbs.File
import qbs.FileInfo
+import qbs.Host
import qbs.ModUtils
import "path-probe.js" as PathProbeConfigure
import "../../../modules/typescript/typescript.js" as TypeScript
@@ -60,23 +61,29 @@ BinaryProbe {
var selectors;
var results = PathProbeConfigure.configure(
selectors, names, nameSuffixes, nameFilter, candidateFilter, searchPaths,
- pathSuffixes, platformSearchPaths, environmentPaths, platformEnvironmentPaths,
- pathListSeparator);
+ pathSuffixes, platformSearchPaths, environmentPaths, platformEnvironmentPaths);
- var v = new ModUtils.EnvironmentVariable("PATH", pathListSeparator,
- hostOS.contains("windows"));
+ var v = new ModUtils.EnvironmentVariable("PATH", FileInfo.pathListSeparator(),
+ Host.os().contains("windows"));
v.prepend(interpreterPath);
- var result = results.files[0];
- result.version = results.found
- ? TypeScript.findTscVersion(result.filePath, v.value)
- : undefined;
- if (FileInfo.fromNativeSeparators(packageManagerBinPath) !== result.path ||
- !File.exists(FileInfo.fromNativeSeparators(packageManagerRootPath, "typescript"))) {
- result = { found: false };
- }
+ var resultsMapper = function(result) {
+ result.version = result.found
+ ? TypeScript.findTscVersion(result.filePath, v.value)
+ : undefined;
+ if (FileInfo.fromNativeSeparators(packageManagerBinPath) !== result.path ||
+ !File.exists(
+ FileInfo.fromNativeSeparators(packageManagerRootPath, "typescript"))) {
+ result = { found: false };
+ }
+ return result;
+ };
+ results.files = results.files.map(resultsMapper);
found = results.found;
+ allResults = results.files;
+
+ var result = results.files[0];
candidatePaths = result.candidatePaths;
path = result.path;
filePath = result.filePath;
diff --git a/share/qbs/imports/qbs/Probes/WatcomProbe.qbs b/share/qbs/imports/qbs/Probes/WatcomProbe.qbs
new file mode 100644
index 000000000..3ea22acb3
--- /dev/null
+++ b/share/qbs/imports/qbs/Probes/WatcomProbe.qbs
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+import qbs.File
+import qbs.Host
+import qbs.ModUtils
+import "../../../modules/cpp/watcom.js" as WATCOM
+
+PathProbe {
+ // Inputs
+ property string compilerFilePath
+ property stringList enableDefinesByLanguage
+
+ property string _pathListSeparator
+ property string _toolchainInstallPath
+ property string _targetPlatform
+ property string _targetArchitecture
+
+ // Outputs
+ property string architecture
+ property string endianness
+ property string targetPlatform
+ property int versionMajor
+ property int versionMinor
+ property int versionPatch
+ property stringList includePaths
+ property var compilerDefinesByLanguage
+ property var environment
+
+ configure: {
+ compilerDefinesByLanguage = {};
+
+ if (!File.exists(compilerFilePath)) {
+ found = false;
+ return;
+ }
+
+ var languages = enableDefinesByLanguage;
+ if (!languages || languages.length === 0)
+ languages = ["c"];
+
+ environment = WATCOM.guessEnvironment(Host.os(), _targetPlatform, _targetArchitecture,
+ _toolchainInstallPath, _pathListSeparator);
+
+ includePaths = environment["INCLUDE"].split(_pathListSeparator).filter(function(path) {
+ return File.exists(path);
+ });
+
+ for (var i = 0; i < languages.length; ++i) {
+ var tag = languages[i];
+ compilerDefinesByLanguage[tag] = WATCOM.dumpMacros(
+ environment, compilerFilePath,
+ _targetPlatform, _targetArchitecture, tag);
+ }
+
+ var macros = compilerDefinesByLanguage["c"]
+ || compilerDefinesByLanguage["cpp"];
+
+ endianness = macros["__BIG_ENDIAN"] ? "big" : "little";
+ architecture = ModUtils.guessArchitecture(macros);
+ targetPlatform = ModUtils.guessTargetPlatform(macros);
+
+ var version = WATCOM.guessVersion(macros);
+ if (version) {
+ versionMajor = version.major;
+ versionMinor = version.minor;
+ versionPatch = version.patch;
+ found = !!architecture && !!targetPlatform;
+ }
+ }
+}
diff --git a/share/qbs/imports/qbs/Probes/XcodeLocationProbe.qbs b/share/qbs/imports/qbs/Probes/XcodeLocationProbe.qbs
new file mode 100644
index 000000000..3401315f7
--- /dev/null
+++ b/share/qbs/imports/qbs/Probes/XcodeLocationProbe.qbs
@@ -0,0 +1,47 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Ivan Komissarov (abbapoh@gmail.com)
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+import qbs.Process
+
+Probe {
+ property path developerPath
+ configure: {
+ var p = new Process();
+ try {
+ p.exec("/usr/bin/xcode-select", ["--print-path"], true);
+ developerPath = p.readStdOut().trim();
+ } catch (e) {
+ developerPath = "/Applications/Xcode.app/Contents/Developer";
+ } finally {
+ p.close();
+ found = true;
+ }
+ }
+}
diff --git a/share/qbs/imports/qbs/Probes/XcodeProbe.qbs b/share/qbs/imports/qbs/Probes/XcodeProbe.qbs
index e0ed99346..9a0d01072 100644
--- a/share/qbs/imports/qbs/Probes/XcodeProbe.qbs
+++ b/share/qbs/imports/qbs/Probes/XcodeProbe.qbs
@@ -48,6 +48,7 @@ Probe {
// Outputs
property var architectureSettings
property var availableSdks
+ property var platformSettings
property string xcodeVersion
configure: {
@@ -88,7 +89,7 @@ Probe {
architectureSettings = {};
var archSpecsPath = Xcode.archsSpecsPath(xcodeVersion, targetOS, platformType,
- platformPath, devicePlatformPath);
+ platformPath, devicePlatformPath, developerPath);
var archSpecsReader = new Xcode.XcodeArchSpecsReader(archSpecsPath);
archSpecsReader.getArchitectureSettings().map(function (setting) {
var val = archSpecsReader.getArchitectureSettingValue(setting);
@@ -97,6 +98,8 @@ Probe {
});
availableSdks = Xcode.sdkInfoList(sdksPath);
+ var platformInfoPlist = FileInfo.joinPaths(platformPath, "Info.plist");
+ platformSettings = Xcode.platformInfo(platformInfoPlist);
found = !!xcodeVersion;
}
}
diff --git a/share/qbs/imports/qbs/Probes/path-probe.js b/share/qbs/imports/qbs/Probes/path-probe.js
index a997f77f2..1858f5222 100644
--- a/share/qbs/imports/qbs/Probes/path-probe.js
+++ b/share/qbs/imports/qbs/Probes/path-probe.js
@@ -36,16 +36,16 @@ var ModUtils = require("qbs.ModUtils");
function asStringList(key, value) {
if (typeof(value) === "string")
return [value];
- if (Array.isArray(value))
+ if (value instanceof Array)
return value;
throw key + " must be a string or a stringList";
}
-function canonicalSelectors(selectors) {
+function canonicalSelectors(selectors, nameSuffixes) {
var mapper = function(selector) {
if (typeof(selector) === "string")
return {names : [selector]};
- if (Array.isArray(selector))
+ if (selector instanceof Array)
return {names : selector};
// dict
if (!selector.names)
@@ -53,14 +53,27 @@ function canonicalSelectors(selectors) {
selector.names = asStringList("names", selector.names);
if (selector.nameSuffixes)
selector.nameSuffixes = asStringList("nameSuffixes", selector.nameSuffixes);
+ else
+ selector.nameSuffixes = nameSuffixes;
return selector;
};
return selectors.map(mapper);
}
+function pathsFromEnvs(envs, pathListSeparator) {
+ envs = envs || [];
+ var result = [];
+ for (var i = 0; i < envs.length; ++i) {
+ var value = Environment.getEnv(envs[i]) || '';
+ if (value.length > 0)
+ result = result.concat(value.split(pathListSeparator));
+ }
+ return result;
+}
+
function configure(selectors, names, nameSuffixes, nameFilter, candidateFilter,
searchPaths, pathSuffixes, platformSearchPaths, environmentPaths,
- platformEnvironmentPaths, pathListSeparator) {
+ platformEnvironmentPaths) {
var result = { found: false, files: [] };
if (!selectors && !names)
throw '"names" or "selectors" must be specified';
@@ -70,7 +83,7 @@ function configure(selectors, names, nameSuffixes, nameFilter, candidateFilter,
{names: names, nameSuffixes: nameSuffixes}
];
} else {
- selectors = canonicalSelectors(selectors);
+ selectors = canonicalSelectors(selectors, nameSuffixes);
}
if (nameFilter) {
@@ -88,14 +101,11 @@ function configure(selectors, names, nameSuffixes, nameFilter, candidateFilter,
});
// FIXME: Suggest how to obtain paths from system
- var _paths = ModUtils.concatAll(searchPaths, platformSearchPaths);
- // FIXME: Add getenv support
- var envs = ModUtils.concatAll(platformEnvironmentPaths, environmentPaths);
- for (var i = 0; i < envs.length; ++i) {
- var value = Environment.getEnv(envs[i]) || '';
- if (value.length > 0)
- _paths = _paths.concat(value.split(pathListSeparator));
- }
+ var _paths = ModUtils.concatAll(
+ pathsFromEnvs(environmentPaths, FileInfo.pathListSeparator()),
+ searchPaths,
+ pathsFromEnvs(platformEnvironmentPaths, FileInfo.pathListSeparator()),
+ platformSearchPaths);
var _suffixes = ModUtils.concatAll('', pathSuffixes);
_paths = _paths.map(function(p) { return FileInfo.fromNativeSeparators(p); });
_suffixes = _suffixes.map(function(p) { return FileInfo.fromNativeSeparators(p); });
diff --git a/share/qbs/imports/qbs/Probes/qbs-pkg-config-probe.js b/share/qbs/imports/qbs/Probes/qbs-pkg-config-probe.js
new file mode 100644
index 000000000..d382dfb02
--- /dev/null
+++ b/share/qbs/imports/qbs/Probes/qbs-pkg-config-probe.js
@@ -0,0 +1,118 @@
+/****************************************************************************
+**
+** Copyright (C) 2023 Ivan Komissarov (abbapoh@gmail.com)
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+var Environment = require("qbs.Environment");
+var File = require("qbs.File");
+var FileInfo = require("qbs.FileInfo");
+var PkgConfig = require("qbs.PkgConfig");
+var ProviderUtils = require("qbs.ProviderUtils");
+var Process = require("qbs.Process");
+
+function getQmakePaths(pkg) {
+ var packageName = pkg.baseFileName;
+ if (packageName === "QtCore"
+ || packageName === "Qt5Core"
+ || packageName === "Qt6Core") {
+ var binDir = pkg.variables["bindir"] || pkg.variables["host_bins"];
+ if (!binDir) {
+ if (packageName === "QtCore") { // Qt4 does not have host_bins
+ var mocLocation = pkg.variables["moc_location"];
+ if (!mocLocation) {
+ console.warn("No moc_location variable in " + packageName);
+ return;
+ }
+ binDir = FileInfo.path(mocLocation);
+ } else {
+ console.warn("No 'bindir' or 'host_bins' variable in " + packageName);
+ return;
+ }
+ }
+ var suffix = FileInfo.executableSuffix();
+ return [FileInfo.joinPaths(binDir, "qmake" + suffix)];
+ }
+}
+
+function configure(
+ executableFilePath, extraPaths, libDirs, staticMode, definePrefix, sysroot) {
+
+ var result = {};
+ result.packages = [];
+ result.packagesByModuleName = {};
+ result.brokenPackages = [];
+ result.qtInfos = [];
+
+ var options = {};
+ options.libDirs = libDirs;
+ options.sysroot = sysroot;
+ options.definePrefix = definePrefix;
+ if (options.sysroot)
+ options.allowSystemLibraryPaths = true;
+ options.staticMode = staticMode;
+ options.extraPaths = extraPaths;
+ if (options.sysroot && !options.libDirs) {
+ options.libDirs = [
+ options.sysroot + "/usr/lib/pkgconfig",
+ options.sysroot + "/usr/share/pkgconfig"
+ ];
+ }
+ if (!options.libDirs) {
+ // if we have pkg-config/pkgconf installed, let's ask it for its search paths (since
+ // built-in search paths can differ between platforms)
+ if (executableFilePath) {
+ var p = new Process()
+ if (p.exec(executableFilePath, ['pkg-config', '--variable=pc_path']) === 0) {
+ var stdout = p.readStdOut().trim();
+ options.libDirs = stdout ? stdout.split(FileInfo.pathListSeparator()): [];
+ var installDir = FileInfo.path(executableFilePath);
+ options.libDirs = options.libDirs.map(function(path){
+ if (FileInfo.isAbsolutePath(path))
+ return path;
+ return FileInfo.cleanPath(FileInfo.joinPaths(installDir, path));
+ });
+ }
+ }
+ }
+ var pkgConfig = new PkgConfig(options);
+ result.packages = pkgConfig.packages();
+ for (var packageName in result.packages) {
+ var pkg = result.packages[packageName];
+ var moduleName = ProviderUtils.pkgConfigToModuleName(packageName);
+ result.packagesByModuleName[moduleName] = pkg;
+
+ if (packageName.startsWith("Qt")) {
+ if (!sysroot) {
+ var qmakePaths = getQmakePaths(pkg);
+ if (qmakePaths !== undefined)
+ result.qmakePaths = qmakePaths;
+ }
+ }
+ }
+ return result;
+}
diff --git a/share/qbs/imports/qbs/Probes/qmake-probe.js b/share/qbs/imports/qbs/Probes/qmake-probe.js
new file mode 100644
index 000000000..746914e20
--- /dev/null
+++ b/share/qbs/imports/qbs/Probes/qmake-probe.js
@@ -0,0 +1,1256 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qbs.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+var Environment = require("qbs.Environment");
+var File = require("qbs.File");
+var FileInfo = require("qbs.FileInfo");
+var Host = require("qbs.Host");
+var Process = require("qbs.Process");
+var ProviderUtils = require("qbs.ProviderUtils");
+var TextFile = require("qbs.TextFile");
+var Utilities = require("qbs.Utilities");
+
+function splitNonEmpty(s, c) { return s.split(c).filter(function(e) { return e; }); }
+
+function getQmakeFilePaths(qmakeFilePaths) {
+ if (qmakeFilePaths && qmakeFilePaths.length > 0)
+ return qmakeFilePaths;
+ console.info("Detecting Qt installations...");
+ var filePaths = [];
+ var pathValue = Environment.getEnv("PATH");
+ if (pathValue) {
+ var dirs = splitNonEmpty(pathValue, FileInfo.pathListSeparator());
+ for (var i = 0; i < dirs.length; ++i) {
+ var candidate = FileInfo.joinPaths(dirs[i], "qmake" + FileInfo.executableSuffix());
+ var canonicalCandidate = FileInfo.canonicalPath(candidate);
+ if (!canonicalCandidate || !File.exists(canonicalCandidate))
+ continue;
+ if (FileInfo.completeBaseName(canonicalCandidate) !== "qtchooser")
+ candidate = canonicalCandidate;
+ if (!filePaths.contains(candidate)) {
+ console.info("Found Qt at '" + FileInfo.toNativeSeparators(candidate) + "'.");
+ filePaths.push(candidate);
+ }
+ }
+ }
+ if (filePaths.length === 0) {
+ console.warn("Could not find any qmake executables in PATH. Either make sure a qmake "
+ + "executable is present in PATH or set the moduleProviders.Qt.qmakeFilePaths property "
+ + "to point to a qmake executable.");
+ }
+ return filePaths;
+}
+
+function queryQmake(qmakeFilePath) {
+ var qmakeProcess = new Process;
+ qmakeProcess.exec(qmakeFilePath, ["-query"]);
+ if (qmakeProcess.exitCode() !== 0) {
+ throw "The qmake executable '" + FileInfo.toNativeSeparators(qmakeFilePath)
+ + "' failed with exit code " + qmakeProcess.exitCode() + ".";
+ }
+ var queryResult = {};
+ while (!qmakeProcess.atEnd()) {
+ var line = qmakeProcess.readLine();
+ var index = (line || "").indexOf(":");
+ if (index !== -1)
+ queryResult[line.slice(0, index)] = line.slice(index + 1).trim();
+ }
+ return queryResult;
+}
+
+function pathQueryValue(queryResult, key) {
+ var p = queryResult[key];
+ if (p)
+ return FileInfo.fromNativeSeparators(p);
+}
+
+function readFileContent(filePath) {
+ var f = new TextFile(filePath, TextFile.ReadOnly);
+ var content = f.readAll();
+ f.close();
+ return content;
+}
+
+// TODO: Don't do the split every time...
+function configVariable(configContent, key) {
+ var configContentLines = configContent.split('\n');
+ var regexp = new RegExp("^\\s*" + key + "\\s*\\+{0,1}=(.*)");
+ for (var i = 0; i < configContentLines.length; ++i) {
+ var line = configContentLines[i];
+ var match = regexp.exec(line);
+ if (match)
+ return match[1].trim();
+ }
+}
+
+function configVariableItems(configContent, key) {
+ return splitNonEmpty(configVariable(configContent, key), ' ');
+}
+
+function msvcCompilerVersionForYear(year) {
+ var mapping = {
+ "2005": "14", "2008": "15", "2010": "16", "2012": "17", "2013": "18", "2015": "19",
+ "2017": "19.1", "2019": "19.2"
+ };
+ return mapping[year];
+}
+
+function msvcCompilerVersionFromMkspecName(mkspecName) {
+ return msvcCompilerVersionForYear(mkspecName.slice(msvcPrefix().length));
+}
+
+function addQtBuildVariant(qtProps, buildVariantName) {
+ if (qtProps.qtConfigItems.contains(buildVariantName))
+ qtProps.buildVariant.push(buildVariantName);
+}
+
+function checkForStaticBuild(qtProps) {
+ if (qtProps.qtMajorVersion >= 5)
+ return qtProps.qtConfigItems.contains("static");
+ if (qtProps.frameworkBuild)
+ return false; // there are no Qt4 static frameworks
+ var isWin = qtProps.mkspecName.startsWith("win");
+ var libDir = isWin ? qtProps.binaryPath : qtProps.libraryPath;
+ var coreLibFiles = File.directoryEntries(libDir, File.Files)
+ .filter(function(fp) { return fp.contains("Core"); });
+ if (coreLibFiles.length === 0)
+ throw "Could not determine whether Qt is a static build.";
+ for (var i = 0; i < coreLibFiles.length; ++i) {
+ if (Utilities.isSharedLibrary(coreLibFiles[i]))
+ return false;
+ }
+ return true;
+}
+
+function guessMinimumWindowsVersion(qtProps) {
+ if (qtProps.mkspecName.startsWith("winrt-"))
+ return "10.0";
+ if (!ProviderUtils.isDesktopWindowsQt(qtProps))
+ return "";
+ if (qtProps.qtMajorVersion >= 6)
+ return "10.0";
+ if (qtProps.architecture === "x86_64" || qtProps.architecture === "ia64")
+ return "5.2"
+ var match = qtProps.mkspecName.match(/^win32-msvc(\d+)$/);
+ if (match) {
+ var msvcVersion = match[1];
+ if (msvcVersion < 2012)
+ return "5.0";
+ return "5.1";
+ }
+ return qtProps.qtMajorVersion < 5 ? "5.0" : "5.1";
+}
+
+function fillEntryPointLibs(qtProps, debug) {
+ result = [];
+ var isMinGW = ProviderUtils.isMinGwQt(qtProps);
+
+ // Some Linux distributions rename the qtmain library.
+ var qtMainCandidates = ["qtmain"];
+ if (isMinGW && qtProps.qtMajorVersion === 5)
+ qtMainCandidates.push("qt5main");
+ if (qtProps.qtMajorVersion === 6)
+ qtMainCandidates.push("Qt6EntryPoint");
+
+ for (var i = 0; i < qtMainCandidates.length; ++i) {
+ var baseNameCandidate = qtMainCandidates[i];
+ var qtmain = qtProps.libraryPath + '/';
+ if (isMinGW)
+ qtmain += "lib";
+ qtmain += baseNameCandidate + qtProps.qtLibInfix;
+ if (debug && ProviderUtils.qtNeedsDSuffix(qtProps))
+ qtmain += 'd';
+ if (isMinGW) {
+ qtmain += ".a";
+ } else {
+ qtmain += ".lib";
+ if (Utilities.versionCompare(qtProps.qtVersion, "5.4.0") >= 0)
+ result.push("Shell32.lib");
+ }
+ if (File.exists(qtmain)) {
+ result.push(qtmain);
+ break;
+ }
+ }
+ if (result.length === 0) {
+ console.warn("Could not find the qtmain library at '"
+ + FileInfo.toNativeSeparators(qtProps.libraryPath)
+ + "'. You will not be able to link Qt applications.");
+ }
+ return result;
+}
+
+function getQtProperties(qmakeFilePath) {
+ var queryResult = queryQmake(qmakeFilePath);
+ var qtProps = {};
+ qtProps.installPrefixPath = pathQueryValue(queryResult, "QT_INSTALL_PREFIX");
+ qtProps.documentationPath = pathQueryValue(queryResult, "QT_INSTALL_DOCS");
+ qtProps.includePath = pathQueryValue(queryResult, "QT_INSTALL_HEADERS");
+ qtProps.libraryPath = pathQueryValue(queryResult, "QT_INSTALL_LIBS");
+ qtProps.hostLibraryPath = pathQueryValue(queryResult, "QT_HOST_LIBS");
+ qtProps.binaryPath = pathQueryValue(queryResult, "QT_HOST_BINS")
+ || pathQueryValue(queryResult, "QT_INSTALL_BINS");
+ qtProps.installPath = pathQueryValue(queryResult, "QT_INSTALL_BINS");
+ qtProps.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 (Utilities.versionCompare(qtProps.qtVersion, "6") >= 0) {
+ qtProps.libExecPath = pathQueryValue(queryResult, "QT_HOST_LIBEXECS")
+ || pathQueryValue(queryResult, "QT_INSTALL_LIBEXECS");
+ }
+
+ // QML tools were only moved in Qt 6.2.
+ qtProps.qmlLibExecPath = Utilities.versionCompare(qtProps.qtVersion, "6.2") >= 0
+ ? qtProps.libExecPath : qtProps.binaryPath;
+
+ // qhelpgenerator was only moved in Qt 6.3.
+ qtProps.helpGeneratorLibExecPath = Utilities.versionCompare(qtProps.qtVersion, "6.3") >= 0
+ ? qtProps.libExecPath : qtProps.binaryPath;
+
+ if (!File.exists(qtProps.mkspecBasePath))
+ throw "Cannot extract the mkspecs directory.";
+
+ var qconfigContent = readFileContent(FileInfo.joinPaths(qtProps.mkspecBasePath,
+ "qconfig.pri"));
+ qtProps.qtMajorVersion = parseInt(configVariable(qconfigContent, "QT_MAJOR_VERSION"));
+ qtProps.qtMinorVersion = parseInt(configVariable(qconfigContent, "QT_MINOR_VERSION"));
+ qtProps.qtPatchVersion = parseInt(configVariable(qconfigContent, "QT_PATCH_VERSION"));
+ qtProps.qtNameSpace = configVariable(qconfigContent, "QT_NAMESPACE");
+ qtProps.qtLibInfix = configVariable(qconfigContent, "QT_LIBINFIX") || "";
+ qtProps.architecture = configVariable(qconfigContent, "QT_TARGET_ARCH")
+ || configVariable(qconfigContent, "QT_ARCH") || "x86";
+ qtProps.configItems = configVariableItems(qconfigContent, "CONFIG");
+ qtProps.qtConfigItems = configVariableItems(qconfigContent, "QT_CONFIG");
+
+ // retrieve the mkspec
+ if (qtProps.qtMajorVersion >= 5) {
+ qtProps.mkspecName = queryResult.QMAKE_XSPEC;
+ qtProps.mkspecPath = FileInfo.joinPaths(qtProps.mkspecBasePath, qtProps.mkspecName);
+ if (mkspecsBaseSrcPath && !File.exists(qtProps.mkspecPath))
+ qtProps.mkspecPath = FileInfo.joinPaths(mkspecsBaseSrcPath, qtProps.mkspecName);
+ } else {
+ if (Host.os().contains("windows")) {
+ var baseDirPath = FileInfo.joinPaths(qtProps.mkspecBasePath, "default");
+ var fileContent = readFileContent(FileInfo.joinPaths(baseDirPath, "qmake.conf"));
+ qtProps.mkspecPath = configVariable(fileContent, "QMAKESPEC_ORIGINAL");
+ if (!File.exists(qtProps.mkspecPath)) {
+ // Work around QTBUG-28792.
+ // The value of QMAKESPEC_ORIGINAL is wrong for MinGW packages. Y u h8 me?
+ var match = fileContent.exec(/\binclude\(([^)]+)\/qmake\.conf\)/m);
+ if (match) {
+ qtProps.mkspecPath = FileInfo.cleanPath(FileInfo.joinPaths(
+ baseDirPath, match[1]));
+ }
+ }
+ } else {
+ qtProps.mkspecPath = FileInfo.canonicalPath(
+ FileInfo.joinPaths(qtProps.mkspecBasePath, "default"));
+ }
+
+ // E.g. in qmake.conf for Qt 4.8/mingw we find this gem:
+ // QMAKESPEC_ORIGINAL=C:\\Qt\\Qt\\4.8\\mingw482\\mkspecs\\win32-g++
+ qtProps.mkspecPath = FileInfo.cleanPath(qtProps.mkspecPath);
+
+ qtProps.mkspecName = qtProps.mkspecPath;
+ var idx = qtProps.mkspecName.lastIndexOf('/');
+ if (idx !== -1)
+ qtProps.mkspecName = qtProps.mkspecName.slice(idx + 1);
+ }
+ if (!File.exists(qtProps.mkspecPath))
+ throw "mkspec '" + FileInfo.toNativeSeparators(qtProps.mkspecPath) + "' does not exist";
+
+ // Starting with qt 5.14, android sdk provides multi-abi
+ if (Utilities.versionCompare(qtProps.qtVersion, "5.14.0") >= 0
+ && qtProps.mkspecPath.contains("android")) {
+ var qdeviceContent = readFileContent(FileInfo.joinPaths(qtProps.mkspecBasePath,
+ "qdevice.pri"));
+ qtProps.androidAbis = configVariable(qdeviceContent, "DEFAULT_ANDROID_ABIS").split(' ');
+ }
+
+ // determine MSVC version
+ if (ProviderUtils.isMsvcQt(qtProps)) {
+ var msvcMajor = configVariable(qconfigContent, "QT_MSVC_MAJOR_VERSION");
+ var msvcMinor = configVariable(qconfigContent, "QT_MSVC_MINOR_VERSION");
+ var msvcPatch = configVariable(qconfigContent, "QT_MSVC_PATCH_VERSION");
+ if (msvcMajor && msvcMinor && msvcPatch)
+ qtProps.msvcVersion = msvcMajor + "." + msvcMinor + "." + msvcPatch;
+ else
+ qtProps.msvcVersion = msvcCompilerVersionFromMkspecName(qtProps.mkspecName);
+ }
+
+ // determine whether we have a framework build
+ qtProps.frameworkBuild = qtProps.mkspecPath.contains("macx")
+ && qtProps.configItems.contains("qt_framework");
+
+ // determine whether Qt is built with debug, release or both
+ qtProps.buildVariant = [];
+ addQtBuildVariant(qtProps, "debug");
+ addQtBuildVariant(qtProps, "release");
+
+ qtProps.staticBuild = checkForStaticBuild(qtProps);
+
+ // determine whether user apps require C++11
+ if (qtProps.qtConfigItems.contains("c++11") && qtProps.staticBuild)
+ qtProps.configItems.push("c++11");
+
+ // Set the minimum operating system versions appropriate for this Qt version
+ qtProps.windowsVersion = guessMinimumWindowsVersion(qtProps);
+ if (qtProps.windowsVersion) { // Is target OS Windows?
+ if (qtProps.buildVariant.contains("debug"))
+ qtProps.entryPointLibsDebug = fillEntryPointLibs(qtProps, true);
+ if (qtProps.buildVariant.contains("release"))
+ qtProps.entryPointLibsRelease = fillEntryPointLibs(qtProps, false);
+ } else if (qtProps.mkspecPath.contains("macx")) {
+ if (qtProps.qtMajorVersion >= 5) {
+ // Since Qt 6.7.1, QMAKE_MACOSX|IOS_DEPLOYMENT_TARGET is no longer present in
+ // qmake.conf. But it is also present in qconfig.pri, so first try to read it from there
+ qtProps.macosVersion = configVariable(qconfigContent, "QMAKE_MACOSX_DEPLOYMENT_TARGET");
+ qtProps.iosVersion = configVariable(qconfigContent, "QMAKE_IOS_DEPLOYMENT_TARGET");
+
+ // Next, we override the value from qmake.conf, if present there
+ // Note, that TVOS/WATCHOS variables are only present in qmake.conf (as of Qt 6.7.1)
+ var lines = getFileContentsRecursively(FileInfo.joinPaths(qtProps.mkspecPath,
+ "qmake.conf"));
+ for (var i = 0; i < lines.length; ++i) {
+ var line = lines[i].trim();
+ match = line.match
+ (/^QMAKE_(MACOSX|IOS|TVOS|WATCHOS)_DEPLOYMENT_TARGET\s*=\s*(.*)\s*$/);
+ if (match) {
+ var platform = match[1];
+ var version = match[2];
+ if (platform === "MACOSX")
+ qtProps.macosVersion = version;
+ else if (platform === "IOS")
+ qtProps.iosVersion = version;
+ else if (platform === "TVOS")
+ qtProps.tvosVersion = version;
+ else if (platform === "WATCHOS")
+ qtProps.watchosVersion = version;
+ }
+ }
+ var isMac = qtProps.mkspecName !== "macx-ios-clang"
+ && qtProps.mkspecName !== "macx-tvos-clang"
+ && qtProps.mkspecName !== "macx-watchos-clang";
+ if (isMac) {
+ // Qt 5.0.x placed the minimum version in a different file
+ if (!qtProps.macosVersion)
+ qtProps.macosVersion = "10.6";
+
+ // If we're using C++11 with libc++, make sure the deployment target is >= 10.7
+ if (Utilities.versionCompare(qtProps.macosVersion, "10, 7") < 0
+ && qtProps.qtConfigItems.contains("c++11")) {
+ qtProps.macosVersion = "10.7";
+ }
+ }
+ } else if (qtProps.qtMajorVersion === 4 && qtProps.qtMinorVersion >= 6) {
+ var qconfigDir = qtProps.frameworkBuild
+ ? FileInfo.joinPaths(qtProps.libraryPath, "QtCore.framework", "Headers")
+ : FileInfo.joinPaths(qtProps.includePath, "Qt");
+ try {
+ var qconfig = new TextFile(FileInfo.joinPaths(qconfigDir, "qconfig.h"),
+ TextFile.ReadOnly);
+ var qtCocoaBuild = false;
+ var ok = true;
+ do {
+ line = qconfig.readLine();
+ if (line.match(/\s*#define\s+QT_MAC_USE_COCOA\s+1\s*/)) {
+ qtCocoaBuild = true;
+ break;
+ }
+ } while (!qconfig.atEof());
+ qtProps.macosVersion = qtCocoaBuild ? "10.5" : "10.4";
+ }
+ catch (e) {}
+ finally {
+ if (qconfig)
+ qconfig.close();
+ }
+ if (!qtProps.macosVersion) {
+ throw "Could not determine whether Qt is using Cocoa or Carbon from '"
+ + FileInfo.toNativeSeparators(qconfig.filePath()) + "'.";
+ }
+ }
+ } else if (qtProps.mkspecPath.contains("android")) {
+ if (qtProps.qtMajorVersion >= 5)
+ qtProps.androidVersion = "2.3";
+ else if (qtProps.qtMajorVersion === 4 && qtProps.qtMinorVersion >= 8)
+ qtProps.androidVersion = "1.6"; // Necessitas
+ }
+ return qtProps;
+}
+
+function makePluginData() {
+ var pluginData = {};
+ pluginData.type = undefined;
+ pluginData.className = undefined;
+ pluginData.autoLoad = true;
+ pluginData["extends"] = [];
+ return pluginData;
+}
+
+function makeQtModuleInfo(name, qbsName, deps) {
+ var moduleInfo = {};
+ moduleInfo.name = name; // As in the path to the headers and ".name" in the pri files.
+ if (moduleInfo.name === undefined)
+ moduleInfo.name = "";
+ moduleInfo.qbsName = qbsName; // Lower-case version without "qt" prefix.
+ moduleInfo.dependencies = deps || []; // qbs names.
+ if (moduleInfo.qbsName && moduleInfo.qbsName !== "core"
+ && !moduleInfo.dependencies.contains("core")) {
+ moduleInfo.dependencies.unshift("core");
+ }
+ moduleInfo.isPrivate = qbsName && qbsName.endsWith("-private");
+ moduleInfo.hasLibrary = !moduleInfo.isPrivate;
+ moduleInfo.isStaticLibrary = false;
+ moduleInfo.isPlugin = false;
+ moduleInfo.mustExist = true;
+ moduleInfo.modulePrefix = ""; // empty value means "Qt".
+ moduleInfo.version = undefined;
+ moduleInfo.includePaths = [];
+ moduleInfo.compilerDefines = [];
+ moduleInfo.staticLibrariesDebug = [];
+ moduleInfo.staticLibrariesRelease = [];
+ moduleInfo.dynamicLibrariesDebug = [];
+ moduleInfo.dynamicLibrariesRelease = [];
+ moduleInfo.linkerFlagsDebug = [];
+ moduleInfo.linkerFlagsRelease = [];
+ moduleInfo.libFilePathDebug = undefined;
+ moduleInfo.libFilePathRelease = undefined;
+ moduleInfo.frameworksDebug = [];
+ moduleInfo.frameworksRelease = [];
+ moduleInfo.frameworkPathsDebug = [];
+ moduleInfo.frameworkPathsRelease = [];
+ moduleInfo.libraryPaths = [];
+ moduleInfo.libDir = "";
+ moduleInfo.config = [];
+ moduleInfo.supportedPluginTypes = [];
+ moduleInfo.pluginData = makePluginData();
+ return moduleInfo;
+}
+
+function frameworkHeadersPath(qtModuleInfo, qtProps) {
+ return FileInfo.joinPaths(qtProps.libraryPath, qtModuleInfo.name + ".framework", "Headers");
+}
+
+function qt4ModuleIncludePaths(qtModuleInfo, qtProps) {
+ var paths = [];
+ if (ProviderUtils.qtIsFramework(qtModuleInfo, qtProps))
+ paths.push(frameworkHeadersPath(qtModuleInfo, qtProps));
+ else
+ paths.push(qtProps.includePath, FileInfo.joinPaths(qtProps.includePath, qtModuleInfo.name));
+ return paths;
+}
+
+// We erroneously called the "testlib" module "test" for quite a while. Let's not punish users
+// for that.
+function addTestModule(modules) {
+ var testModule = makeQtModuleInfo("QtTest", "test", ["testlib"]);
+ testModule.hasLibrary = false;
+ modules.push(testModule);
+}
+
+// See above.
+function addDesignerComponentsModule(modules) {
+ var module = makeQtModuleInfo("QtDesignerComponents", "designercomponents",
+ ["designercomponents-private"]);
+ module.hasLibrary = false;
+ modules.push(module);
+}
+
+function guessLibraryFilePath(prlFilePath, libDir, qtProps) {
+ var baseName = FileInfo.baseName(prlFilePath);
+ var prefixCandidates = ["", "lib"];
+ var suffixCandidates = ["so." + qtProps.qtVersion, "so", "a", "lib", "dll.a"];
+ for (var i = 0; i < prefixCandidates.length; ++i) {
+ var prefix = prefixCandidates[i];
+ for (var j = 0; j < suffixCandidates.length; ++j) {
+ var suffix = suffixCandidates[j];
+ var candidate = FileInfo.joinPaths(libDir, prefix + baseName + '.' + suffix);
+ if (File.exists(candidate))
+ return candidate;
+ }
+ }
+}
+
+function doReplaceQtLibNamesWithFilePath(namePathMap, libList) {
+ for (var i = 0; i < libList.length; ++i) {
+ var lib = libList[i];
+ var path = namePathMap[lib];
+ if (path)
+ libList[i] = path;
+ }
+}
+
+function replaceQtLibNamesWithFilePath(modules, qtProps) {
+ // We don't want to add the libraries for Qt modules via "-l", because of the
+ // danger that a wrong one will be picked up, e.g. from /usr/lib. Instead,
+ // we pull them in using the full file path.
+ var linkerNamesToFilePathsDebug = {};
+ var linkerNamesToFilePathsRelease = {};
+ for (var i = 0; i < modules.length; ++i) {
+ var m = modules[i];
+ linkerNamesToFilePathsDebug[
+ ProviderUtils.qtLibNameForLinker(m, qtProps, true)] = m.libFilePathDebug;
+ linkerNamesToFilePathsRelease[
+ ProviderUtils.qtLibNameForLinker(m, qtProps, false)] = m.libFilePathRelease;
+ }
+ for (i = 0; i < modules.length; ++i) {
+ var module = modules[i];
+ doReplaceQtLibNamesWithFilePath(linkerNamesToFilePathsDebug, module.dynamicLibrariesDebug);
+ doReplaceQtLibNamesWithFilePath(linkerNamesToFilePathsDebug, module.staticLibrariesDebug);
+ doReplaceQtLibNamesWithFilePath(linkerNamesToFilePathsRelease,
+ module.dynamicLibrariesRelease);
+ doReplaceQtLibNamesWithFilePath(linkerNamesToFilePathsRelease,
+ module.staticLibrariesRelease);
+ }
+}
+
+function doSetupLibraries(modInfo, qtProps, debugBuild, nonExistingPrlFiles, androidAbi) {
+ if (!modInfo.hasLibrary)
+ return; // Can happen for Qt4 convenience modules, like "widgets".
+
+ if (debugBuild) {
+ if (!qtProps.buildVariant.contains("debug"))
+ return;
+ var modulesNeverBuiltAsDebug = ["bootstrap", "qmldevtools"];
+ for (var i = 0; i < modulesNeverBuiltAsDebug.length; ++i) {
+ var m = modulesNeverBuiltAsDebug[i];
+ if (modInfo.qbsName === m || modInfo.qbsName === m + "-private")
+ return;
+ }
+ } else if (!qtProps.buildVariant.contains("release")) {
+ return;
+ }
+
+ var libs = modInfo.isStaticLibrary
+ ? (debugBuild ? modInfo.staticLibrariesDebug : modInfo.staticLibrariesRelease)
+ : (debugBuild ? modInfo.dynamicLibrariesDebug : modInfo.dynamicLibrariesRelease);
+ var frameworks = debugBuild ? modInfo.frameworksDebug : modInfo.frameworksRelease;
+ var frameworkPaths = debugBuild ? modInfo.frameworkPathsDebug : modInfo.frameworkPathsRelease;
+ var flags = debugBuild ? modInfo.linkerFlagsDebug : modInfo.linkerFlagsRelease;
+ var libFilePath;
+
+ if (qtProps.mkspecName.contains("ios") && modInfo.isStaticLibrary) {
+ libs.push("z", "m");
+ if (qtProps.qtMajorVersion === 5 && qtProps.qtMinorVersion < 8) {
+ var platformSupportModule = makeQtModuleInfo("QtPlatformSupport", "platformsupport");
+ libs.push(ProviderUtils.qtLibNameForLinker(platformSupportModule, qtProps, debugBuild));
+ }
+ if (modInfo.name === "qios") {
+ flags.push("-force_load", FileInfo.joinPaths(
+ qtProps.pluginPath, "platforms",
+ ProviderUtils.qtLibBaseName(
+ modInfo, "libqios", debugBuild, qtProps) + ".a"));
+ }
+ }
+ var prlFilePath = modInfo.isPlugin
+ ? FileInfo.joinPaths(qtProps.pluginPath, modInfo.pluginData.type)
+ : (modInfo.libDir ? modInfo.libDir : qtProps.libraryPath);
+ var libDir = prlFilePath;
+ if (ProviderUtils.qtIsFramework(modInfo, qtProps)) {
+ prlFilePath = FileInfo.joinPaths(
+ prlFilePath,
+ ProviderUtils.qtLibraryBaseName(modInfo, qtProps, false) + ".framework");
+ libDir = prlFilePath;
+ if (Utilities.versionCompare(qtProps.qtVersion, "5.14") >= 0)
+ prlFilePath = FileInfo.joinPaths(prlFilePath, "Resources");
+ }
+ var baseName = ProviderUtils.qtLibraryBaseName(modInfo, qtProps, debugBuild);
+ if (!qtProps.mkspecName.startsWith("win") && !ProviderUtils.qtIsFramework(modInfo, qtProps))
+ baseName = "lib" + baseName;
+ prlFilePath = FileInfo.joinPaths(prlFilePath, baseName);
+ var isNonStaticQt4OnWindows = qtProps.mkspecName.startsWith("win")
+ && !modInfo.isStaticLibrary && qtProps.qtMajorVersion < 5;
+ if (isNonStaticQt4OnWindows)
+ prlFilePath = prlFilePath.slice(0, prlFilePath.length - 1); // The prl file base name does *not* contain the version number...
+ // qt for android versions 6.0 and 6.1 don't have the architecture suffix in the prl file
+ if (androidAbi.length > 0
+ && modInfo.name !== "QtBootstrap"
+ && (modInfo.name !== "QtQmlDevTools" || modInfo.name === "QtQmlDevTools"
+ && Utilities.versionCompare(qtProps.qtVersion, "6.2") >= 0)
+ && (Utilities.versionCompare(qtProps.qtVersion, "6.0") < 0
+ || Utilities.versionCompare(qtProps.qtVersion, "6.2") >= 0)) {
+ prlFilePath += "_";
+ prlFilePath += androidAbi;
+ }
+
+ prlFilePath += ".prl";
+
+ try {
+ var prlFile = new TextFile(prlFilePath, TextFile.ReadOnly);
+ while (!prlFile.atEof()) {
+ var line = prlFile.readLine().trim();
+ var equalsOffset = line.indexOf('=');
+ if (equalsOffset === -1)
+ continue;
+ if (line.startsWith("QMAKE_PRL_TARGET")) {
+ var isMingw = qtProps.mkspecName.startsWith("win")
+ && qtProps.mkspecName.contains("g++");
+ var isQtVersionBefore56 = qtProps.qtMajorVersion < 5
+ || (qtProps.qtMajorVersion === 5 && qtProps.qtMinorVersion < 6);
+
+ // QMAKE_PRL_TARGET has a "lib" prefix, except for mingw.
+ // Of course, the exception has an exception too: For static libs, mingw *does*
+ // have the "lib" prefix.
+ var libFileName = "";
+ if (isQtVersionBefore56 && qtProps.qtMajorVersion === 5 && isMingw
+ && !modInfo.isStaticLibrary) {
+ libFileName += "lib";
+ }
+
+ libFileName += line.slice(equalsOffset + 1).trim();
+ if (isNonStaticQt4OnWindows)
+ libFileName += 4; // This is *not* part of QMAKE_PRL_TARGET...
+ if (isQtVersionBefore56) {
+ if (qtProps.mkspecName.contains("msvc")) {
+ libFileName += ".lib";
+ } else if (isMingw) {
+ libFileName += ".a";
+ if (!File.exists(FileInfo.joinPaths(libDir, libFileName)))
+ libFileName = libFileName.slice(0, -2) + ".dll";
+ }
+ }
+ libFilePath = FileInfo.joinPaths(libDir, libFileName);
+ continue;
+ }
+ if (line.startsWith("QMAKE_PRL_CONFIG")) {
+ modInfo.config = splitNonEmpty(line.slice(equalsOffset + 1).trim(), ' ');
+ continue;
+ }
+ if (!line.startsWith("QMAKE_PRL_LIBS ="))
+ continue;
+
+ var parts = extractPaths(line.slice(equalsOffset + 1).trim(), prlFilePath);
+ for (i = 0; i < parts.length; ++i) {
+ var part = parts[i];
+ part = part.replace("$$[QT_INSTALL_LIBS]", qtProps.libraryPath);
+ part = part.replace("$$[QT_INSTALL_PLUGINS]", qtProps.pluginPath);
+ part = part.replace("$$[QT_INSTALL_PREFIX]", qtProps.installPrefixPath);
+ if (part.startsWith("-l")) {
+ libs.push(part.slice(2));
+ } else if (part.startsWith("-L")) {
+ modInfo.libraryPaths.push(part.slice(2));
+ } else if (part.startsWith("-F")) {
+ frameworkPaths.push(part.slice(2));
+ } else if (part === "-framework") {
+ if (++i < parts.length)
+ frameworks.push(parts[i]);
+ } else if (part === "-pthread") {
+ // prl files for android have QMAKE_PRL_LIBS = -llog -pthread but the pthread
+ // functionality is included in libc.
+ if (androidAbi.length === 0)
+ libs.push("pthread");
+ } else if (part.startsWith('-')) { // Some other option
+ console.debug("QMAKE_PRL_LIBS contains non-library option '" + part
+ + "' in file '" + prlFilePath + "'");
+ flags.push(part);
+ } else if (part.startsWith("/LIBPATH:")) {
+ libraryPaths.push(part.slice(9).replace(/\\/g, '/'));
+ } else { // Assume it's a file path/name.
+ libs.push(part.replace(/\\/g, '/'));
+ }
+ }
+ }
+ } catch (e) {
+ // qt_ext_lib_extX.pri (usually) don't have a corresponding prl file.
+ // So the pri file variable QMAKE_LIBS_LIBX points to the library
+ if (modInfo.isExternal) {
+ libFilePath = debugBuild ? modInfo.staticLibrariesDebug[0] :
+ modInfo.staticLibrariesRelease[0];
+ }
+ if (!libFilePath || !File.exists(libFilePath))
+ libFilePath = guessLibraryFilePath(prlFilePath, libDir, qtProps);
+ if (nonExistingPrlFiles.contains(prlFilePath))
+ return;
+ nonExistingPrlFiles.push(prlFilePath);
+ if (modInfo.mustExist) {
+ console.warn("Could not open prl file '"
+ + FileInfo.toNativeSeparators(prlFilePath) + "' for module '"
+ + modInfo.name
+ + "' (" + e + "), and failed to deduce the library file path. "
+ + " This module will likely not be usable by qbs.");
+ }
+ }
+ finally {
+ if (prlFile)
+ prlFile.close();
+ }
+
+ if (debugBuild)
+ modInfo.libFilePathDebug = libFilePath;
+ else
+ modInfo.libFilePathRelease = libFilePath;
+}
+
+function setupLibraries(qtModuleInfo, qtProps, nonExistingPrlFiles, androidAbi) {
+ doSetupLibraries(qtModuleInfo, qtProps, true, nonExistingPrlFiles, androidAbi);
+ doSetupLibraries(qtModuleInfo, qtProps, false, nonExistingPrlFiles, androidAbi);
+}
+
+function allQt4Modules(qtProps) {
+ // as per http://doc.qt.io/qt-4.8/modules.html + private stuff.
+ var modules = [];
+
+ var core = makeQtModuleInfo("QtCore", "core");
+ core.compilerDefines.push("QT_CORE_LIB");
+ if (qtProps.qtNameSpace)
+ core.compilerDefines.push("QT_NAMESPACE=" + qtProps.qtNameSpace);
+ modules.push(core,
+ makeQtModuleInfo("QtCore", "core-private", ["core"]),
+ makeQtModuleInfo("QtGui", "gui"),
+ makeQtModuleInfo("QtGui", "gui-private", ["gui"]),
+ makeQtModuleInfo("QtMultimedia", "multimedia", ["gui", "network"]),
+ makeQtModuleInfo("QtMultimedia", "multimedia-private", ["multimedia"]),
+ makeQtModuleInfo("QtNetwork", "network"),
+ makeQtModuleInfo("QtNetwork", "network-private", ["network"]),
+ makeQtModuleInfo("QtOpenGL", "opengl", ["gui"]),
+ makeQtModuleInfo("QtOpenGL", "opengl-private", ["opengl"]),
+ makeQtModuleInfo("QtOpenVG", "openvg", ["gui"]),
+ makeQtModuleInfo("QtScript", "script"),
+ makeQtModuleInfo("QtScript", "script-private", ["script"]),
+ makeQtModuleInfo("QtScriptTools", "scripttools", ["script", "gui"]),
+ makeQtModuleInfo("QtScriptTools", "scripttools-private", ["scripttools"]),
+ makeQtModuleInfo("QtSql", "sql"),
+ makeQtModuleInfo("QtSql", "sql-private", ["sql"]),
+ makeQtModuleInfo("QtSvg", "svg", ["gui"]),
+ makeQtModuleInfo("QtSvg", "svg-private", ["svg"]),
+ makeQtModuleInfo("QtWebKit", "webkit", ["gui", "network"]),
+ makeQtModuleInfo("QtWebKit", "webkit-private", ["webkit"]),
+ makeQtModuleInfo("QtXml", "xml"),
+ makeQtModuleInfo("QtXml", "xml-private", ["xml"]),
+ makeQtModuleInfo("QtXmlPatterns", "xmlpatterns", ["network"]),
+ makeQtModuleInfo("QtXmlPatterns", "xmlpatterns-private", ["xmlpatterns"]),
+ makeQtModuleInfo("QtDeclarative", "declarative", ["gui", "script"]),
+ makeQtModuleInfo("QtDeclarative", "declarative-private", ["declarative"]),
+ makeQtModuleInfo("QtDesigner", "designer", ["gui", "xml"]),
+ makeQtModuleInfo("QtDesigner", "designer-private", ["designer"]),
+ makeQtModuleInfo("QtUiTools", "uitools"),
+ makeQtModuleInfo("QtUiTools", "uitools-private", ["uitools"]),
+ makeQtModuleInfo("QtHelp", "help", ["network", "sql"]),
+ makeQtModuleInfo("QtHelp", "help-private", ["help"]),
+ makeQtModuleInfo("QtTest", "testlib"),
+ makeQtModuleInfo("QtTest", "testlib-private", ["testlib"]));
+ if (qtProps.mkspecName.startsWith("win")) {
+ var axcontainer = makeQtModuleInfo("QAxContainer", "axcontainer");
+ axcontainer.modulePrefix = "Q";
+ axcontainer.isStaticLibrary = true;
+ axcontainer.includePaths.push(FileInfo.joinPaths(qtProps.includePath, "ActiveQt"));
+ modules.push(axcontainer);
+
+ var axserver = makeQtModuleInfo("QAxServer", "axserver");
+ axserver.modulePrefix = "Q";
+ axserver.isStaticLibrary = true;
+ axserver.compilerDefines.push("QAXSERVER");
+ axserver.includePaths.push(FileInfo.joinPaths(qtProps.includePath, "ActiveQt"));
+ modules.push(axserver);
+ } else {
+ modules.push(makeQtModuleInfo("QtDBus", "dbus"));
+ modules.push(makeQtModuleInfo("QtDBus", "dbus-private", ["dbus"]));
+ }
+
+ var designerComponentsPrivate = makeQtModuleInfo(
+ "QtDesignerComponents", "designercomponents-private",
+ ["gui-private", "designer-private"]);
+ designerComponentsPrivate.hasLibrary = true;
+ modules.push(designerComponentsPrivate);
+
+ var phonon = makeQtModuleInfo("Phonon", "phonon");
+ phonon.includePaths = qt4ModuleIncludePaths(phonon, qtProps);
+ modules.push(phonon);
+
+ // Set up include paths that haven't been set up before this point.
+ for (i = 0; i < modules.length; ++i) {
+ var module = modules[i];
+ if (module.includePaths.length > 0)
+ continue;
+ module.includePaths = qt4ModuleIncludePaths(module, qtProps);
+ }
+
+ // Set up compiler defines haven't been set up before this point.
+ for (i = 0; i < modules.length; ++i) {
+ module = modules[i];
+ if (module.compilerDefines.length > 0)
+ continue;
+ module.compilerDefines.push("QT_" + module.qbsName.toUpperCase() + "_LIB");
+ }
+
+ // These are for the convenience of project file authors. It allows them
+ // to add a dependency to e.g. "Qt.widgets" without a version check.
+ var virtualModule = makeQtModuleInfo(undefined, "widgets", ["core", "gui"]);
+ virtualModule.hasLibrary = false;
+ modules.push(virtualModule);
+ virtualModule = makeQtModuleInfo(undefined, "quick", ["declarative"]);
+ virtualModule.hasLibrary = false;
+ modules.push(virtualModule);
+ virtualModule = makeQtModuleInfo(undefined, "concurrent");
+ virtualModule.hasLibrary = false;
+ modules.push(virtualModule);
+ virtualModule = makeQtModuleInfo(undefined, "printsupport", ["core", "gui"]);
+ virtualModule.hasLibrary = false;
+ modules.push(virtualModule);
+
+ addTestModule(modules);
+ addDesignerComponentsModule(modules);
+
+ var modulesThatCanBeDisabled = [
+ "xmlpatterns", "multimedia", "phonon", "svg", "webkit", "script", "scripttools",
+ "declarative", "gui", "dbus", "opengl", "openvg"];
+ var nonExistingPrlFiles = [];
+ for (i = 0; i < modules.length; ++i) {
+ module = modules[i];
+ var name = module.qbsName;
+ var privateIndex = name.indexOf("-private");
+ if (privateIndex !== -1)
+ name = name.slice(0, privateIndex);
+ if (modulesThatCanBeDisabled.contains(name))
+ module.mustExist = false;
+ if (qtProps.staticBuild)
+ module.isStaticLibrary = true;
+ setupLibraries(module, qtProps, nonExistingPrlFiles, "");
+ }
+ replaceQtLibNamesWithFilePath(modules, qtProps);
+
+ return modules;
+}
+
+function getFileContentsRecursively(filePath) {
+ var file = new TextFile(filePath, TextFile.ReadOnly);
+ var lines = splitNonEmpty(file.readAll(), '\n');
+ for (var i = 0; i < lines.length; ++i) {
+ var includeString = "include(";
+ var line = lines[i].trim();
+ if (!line.startsWith(includeString))
+ continue;
+ var offset = includeString.length;
+ var closingParenPos = line.indexOf(')', offset);
+ if (closingParenPos === -1) {
+ console.warn("Invalid include statement in '"
+ + FileInfo.toNativeSeparators(filePath) + "'");
+ continue;
+ }
+ var includedFilePath = line.slice(offset, closingParenPos);
+ if (!FileInfo.isAbsolutePath(includedFilePath))
+ includedFilePath = FileInfo.joinPaths(FileInfo.path(filePath), includedFilePath);
+ var includedContents = getFileContentsRecursively(includedFilePath);
+ var j = i;
+ for (var k = 0; k < includedContents.length; ++k)
+ lines.splice(++j, 0, includedContents[k]);
+ lines.splice(i--, 1);
+ }
+ file.close();
+ return lines;
+}
+
+function extractPaths(rhs, filePath) {
+ var paths = [];
+ var startIndex = 0;
+ for (;;) {
+ while (startIndex < rhs.length && rhs.charAt(startIndex) === ' ')
+ ++startIndex;
+ if (startIndex >= rhs.length)
+ break;
+ var endIndex;
+ if (rhs.charAt(startIndex) === '"') {
+ ++startIndex;
+ endIndex = rhs.indexOf('"', startIndex);
+ if (endIndex === -1) {
+ console.warn("Unmatched quote in file '"
+ + FileInfo.toNativeSeparators(filePath) + "'");
+ break;
+ }
+ } else {
+ endIndex = rhs.indexOf(' ', startIndex + 1);
+ if (endIndex === -1)
+ endIndex = rhs.length;
+ }
+ paths.push(FileInfo.cleanPath(rhs.slice(startIndex, endIndex)
+ .replace("$$PWD", FileInfo.path(filePath))));
+ startIndex = endIndex + 1;
+ }
+ return paths;
+}
+
+function removeDuplicatedDependencyLibs(modules) {
+ var revDeps = {};
+ var currentPath = [];
+ var getLibraries;
+ var getLibFilePath;
+
+ function setupReverseDependencies(modules) {
+ var moduleByName = {};
+ for (var i = 0; i < modules.length; ++i)
+ moduleByName[modules[i].qbsName] = modules[i];
+ for (i = 0; i < modules.length; ++i) {
+ var module = modules[i];
+ for (var j = 0; j < module.dependencies.length; ++j) {
+ var depmod = moduleByName[module.dependencies[j]];
+ if (!depmod)
+ continue;
+ if (!revDeps[depmod.qbsName])
+ revDeps[depmod.qbsName] = [];
+ revDeps[depmod.qbsName].push(module);
+ }
+ }
+ }
+
+ function roots(modules) {
+ var result = [];
+ for (i = 0; i < modules.length; ++i) {
+ var module = modules[i]
+ if (module.dependencies.length === 0)
+ result.push(module);
+ }
+ return result;
+ }
+
+ function traverse(module, libs) {
+ if (currentPath.contains(module))
+ return;
+ currentPath.push(module);
+ var moduleLibraryLists = getLibraries(module);
+ for (var i = 0; i < moduleLibraryLists.length; ++i) {
+ var modLibList = moduleLibraryLists[i];
+ for (j = modLibList.length - 1; j >= 0; --j) {
+ if (libs.contains(modLibList[j]))
+ modLibList.splice(j, 1);
+ }
+ }
+
+ var libFilePath = getLibFilePath(module);
+ if (libFilePath)
+ libs.push(libFilePath);
+ for (i = 0; i < moduleLibraryLists.length; ++i)
+ libs = libs.concat(moduleLibraryLists[i]);
+ libs.sort();
+
+ var deps = revDeps[module.qbsName];
+ for (i = 0; i < (deps || []).length; ++i)
+ traverse(deps[i], libs);
+
+ currentPath.pop();
+ }
+
+ setupReverseDependencies(modules);
+
+ // Traverse the debug variants of modules.
+ getLibraries = function(module) {
+ return [module.dynamicLibrariesDebug, module.staticLibrariesDebug];
+ };
+ getLibFilePath = function(module) { return module.libFilePathDebug; };
+ var rootModules = roots(modules);
+ for (var i = 0; i < rootModules.length; ++i)
+ traverse(rootModules[i], []);
+
+ // Traverse the release variants of modules.
+ getLibraries = function(module) {
+ return [module.dynamicLibrariesRelease, module.staticLibrariesRelease];
+ };
+ getLibFilePath = function(module) { return module.libFilePathRelease; };
+ for (i = 0; i < rootModules.length; ++i)
+ traverse(rootModules[i], []);
+}
+
+function allQt5Modules(qtProps, androidAbi) {
+ var nonExistingPrlFiles = [];
+ var modules = [];
+ var modulesDir = FileInfo.joinPaths(qtProps.mkspecBasePath, "modules");
+ var modulePriFiles = File.directoryEntries(modulesDir, File.Files);
+ for (var i = 0; i < modulePriFiles.length; ++i) {
+ var priFileName = modulePriFiles[i];
+ var priFilePath = FileInfo.joinPaths(modulesDir, priFileName);
+ var externalFileNamePrefix = "qt_ext_";
+ var moduleFileNamePrefix = "qt_lib_";
+ var pluginFileNamePrefix = "qt_plugin_";
+ var moduleFileNameSuffix = ".pri";
+ var fileHasExternalPrefix = priFileName.startsWith(externalFileNamePrefix);
+ var fileHasModulePrefix = priFileName.startsWith(moduleFileNamePrefix);
+ var fileHasPluginPrefix = priFileName.startsWith(pluginFileNamePrefix);
+ if (!fileHasPluginPrefix && !fileHasModulePrefix && !fileHasExternalPrefix
+ || !priFileName.endsWith(moduleFileNameSuffix)) {
+ continue;
+ }
+ var moduleInfo = makeQtModuleInfo();
+ moduleInfo.isPlugin = fileHasPluginPrefix;
+ moduleInfo.isExternal = !moduleInfo.isPlugin && !fileHasModulePrefix;
+ var fileNamePrefix = moduleInfo.isPlugin ? pluginFileNamePrefix : moduleInfo.isExternal
+ ? externalFileNamePrefix : moduleFileNamePrefix;
+ moduleInfo.qbsName = priFileName.slice(fileNamePrefix.length, -moduleFileNameSuffix.length);
+ if (moduleInfo.isPlugin) {
+ moduleInfo.name = moduleInfo.qbsName;
+ moduleInfo.isStaticLibrary = true;
+ }
+ var moduleKeyPrefix = (moduleInfo.isPlugin ? "QT_PLUGIN" : "QT")
+ + '.' + moduleInfo.qbsName + '.';
+ moduleInfo.qbsName = moduleInfo.qbsName.replace("_private", "-private");
+ var hasV2 = false;
+ var hasModuleEntry = false;
+ var lines = getFileContentsRecursively(priFilePath);
+ if (moduleInfo.isExternal) {
+ moduleInfo.name = "qt" + moduleInfo.qbsName;
+ moduleInfo.isStaticLibrary = true;
+ for (var k = 0; k < lines.length; ++k) {
+ var extLine = lines[k].trim();
+ var extFirstEqualsOffset = extLine.indexOf('=');
+ if (extFirstEqualsOffset === -1)
+ continue;
+ var extKey = extLine.slice(0, extFirstEqualsOffset).trim();
+ var extValue = extLine.slice(extFirstEqualsOffset + 1).trim();
+ if (!extKey.startsWith("QMAKE_") || !extValue)
+ continue;
+
+ var elements = extKey.split('_');
+ if (elements.length >= 3) {
+ if (elements[1] === "LIBS") {
+ extValue = extValue.replace("/home/qt/work/qt/qtbase/lib",
+ qtProps.libraryPath);
+ extValue = extValue.replace("$$[QT_INSTALL_LIBS]", qtProps.libraryPath);
+ extValue = extValue.replace("$$[QT_INSTALL_LIBS/get]", qtProps.libraryPath);
+ if (elements.length === 4 ) {
+ if (elements[3] === androidAbi) {
+ moduleInfo.staticLibrariesRelease.push(extValue);
+ moduleInfo.staticLibrariesDebug.push(extValue);
+ }
+ } else if (elements.length === 5 ) {
+ // That's for "x86_64"
+ var abi = elements[3] + '_' + elements[4];
+ if (abi === androidAbi) {
+ moduleInfo.staticLibrariesRelease.push(extValue);
+ moduleInfo.staticLibrariesDebug.push(extValue);
+ }
+ } else {
+ moduleInfo.staticLibrariesRelease.push(extValue);
+ moduleInfo.staticLibrariesDebug.push(extValue);
+ }
+ } else if (elements[1] === "INCDIR") {
+ moduleInfo.includePaths.push(extValue.replace("$$[QT_INSTALL_HEADERS]",
+ qtProps.includePath));
+ }
+ }
+ }
+ moduleInfo.compilerDefines.push("QT_" + moduleInfo.qbsName.toUpperCase() + "_LIB");
+ moduleInfo.mustExist = false;
+ } else {
+ for (var j = 0; j < lines.length; ++j) {
+ var line = lines[j].trim();
+ var firstEqualsOffset = line.indexOf('=');
+ if (firstEqualsOffset === -1)
+ continue;
+ var key = line.slice(0, firstEqualsOffset).trim();
+ var value = line.slice(firstEqualsOffset + 1).trim();
+ if (!key.startsWith(moduleKeyPrefix) || !value)
+ continue;
+ if (key.endsWith(".name")) {
+ moduleInfo.name = value;
+ } else if (key.endsWith(".module")) {
+ hasModuleEntry = true;
+ } else if (key.endsWith(".depends")) {
+ moduleInfo.dependencies = splitNonEmpty(value, ' ');
+ for (var k = 0; k < moduleInfo.dependencies.length; ++k) {
+ moduleInfo.dependencies[k]
+ = moduleInfo.dependencies[k].replace("_private", "-private");
+ }
+ } else if (key.endsWith(".module_config")) {
+ var elems = splitNonEmpty(value, ' ');
+ for (k = 0; k < elems.length; ++k) {
+ var elem = elems[k];
+ if (elem === "no_link")
+ moduleInfo.hasLibrary = false;
+ else if (elem === "staticlib")
+ moduleInfo.isStaticLibrary = true;
+ else if (elem === "internal_module")
+ moduleInfo.isPrivate = true;
+ else if (elem === "v2")
+ hasV2 = true;
+ }
+ } else if (key.endsWith(".includes")) {
+ moduleInfo.includePaths = extractPaths(value, priFilePath);
+ for (k = 0; k < moduleInfo.includePaths.length; ++k) {
+ moduleInfo.includePaths[k] = moduleInfo.includePaths[k]
+ .replace("$$QT_MODULE_INCLUDE_BASE", qtProps.includePath)
+ .replace("$$QT_MODULE_HOST_LIB_BASE", qtProps.hostLibraryPath)
+ .replace("$$QT_MODULE_LIB_BASE", qtProps.libraryPath);
+ }
+ } else if (key.endsWith(".libs")) {
+ var libDirs = extractPaths(value, priFilePath);
+ if (libDirs.length === 1) {
+ moduleInfo.libDir = libDirs[0]
+ .replace("$$QT_MODULE_HOST_LIB_BASE", qtProps.hostLibraryPath)
+ .replace("$$QT_MODULE_LIB_BASE", qtProps.libraryPath);
+ } else {
+ moduleInfo.libDir = qtProps.libraryPath;
+ }
+ } else if (key.endsWith(".DEFINES")) {
+ moduleInfo.compilerDefines = splitNonEmpty(value, ' ');
+ } else if (key.endsWith(".VERSION")) {
+ moduleInfo.version = value;
+ } else if (key.endsWith(".plugin_types")) {
+ moduleInfo.supportedPluginTypes = splitNonEmpty(value, ' ');
+ } else if (key.endsWith(".TYPE")) {
+ moduleInfo.pluginData.type = value;
+ } else if (key.endsWith(".EXTENDS")) {
+ moduleInfo.pluginData["extends"] = splitNonEmpty(value, ' ');
+ for (k = 0; k < moduleInfo.pluginData["extends"].length; ++k) {
+ if (moduleInfo.pluginData["extends"][k] === "-") {
+ moduleInfo.pluginData["extends"].splice(k, 1);
+ moduleInfo.pluginData.autoLoad = false;
+ break;
+ }
+ }
+ } else if (key.endsWith(".CLASS_NAME")) {
+ moduleInfo.pluginData.className = value;
+ }
+ }
+ }
+ if (hasV2 && !hasModuleEntry && !moduleInfo.isStaticLibrary)
+ moduleInfo.hasLibrary = false;
+
+ // Fix include paths for Apple frameworks.
+ // The qt_lib_XXX.pri files contain wrong values for versions < 5.6.
+ if (!hasV2 && ProviderUtils.qtIsFramework(moduleInfo, qtProps)) {
+ moduleInfo.includePaths = [];
+ var baseIncDir = frameworkHeadersPath(moduleInfo, qtProps);
+ if (moduleInfo.isPrivate) {
+ baseIncDir = FileInfo.joinPaths(baseIncDir, moduleInfo.version);
+ moduleInfo.includePaths.push(baseIncDir,
+ FileInfo.joinPaths(baseIncDir, moduleInfo.name));
+ } else {
+ moduleInfo.includePaths.push(baseIncDir);
+ }
+ }
+
+ setupLibraries(moduleInfo, qtProps, nonExistingPrlFiles, androidAbi);
+
+ modules.push(moduleInfo);
+ if (moduleInfo.qbsName === "testlib")
+ addTestModule(modules);
+ if (moduleInfo.qbsName === "designercomponents-private")
+ addDesignerComponentsModule(modules);
+ }
+
+ replaceQtLibNamesWithFilePath(modules, qtProps);
+ removeDuplicatedDependencyLibs(modules);
+
+ return modules;
+}
+
+function getQtInfo(qmakeFilePath) {
+ if (!File.exists(qmakeFilePath)) {
+ throw "The specified qmake file path '"
+ + FileInfo.toNativeSeparators(qmakeFilePath) + "' does not exist.";
+ }
+ var qtProps = getQtProperties(qmakeFilePath);
+ var androidAbis = [];
+ if (qtProps.androidAbis !== undefined) {
+ // Multiple androidAbis detected: Qt >= 5.14
+ androidAbis = qtProps.androidAbis;
+ } else {
+ // Single abi detected: Qt < 5.14
+ androidAbis.push('');
+ }
+ if (androidAbis.length > 1)
+ console.info("Qt with multiple abi detected: '" + androidAbis + "'");
+
+ var result = {};
+ result.qtProps = qtProps;
+ result.abiInfos = [];
+ result.qmakeFilePath = qmakeFilePath;
+ for (a = 0; a < androidAbis.length; ++a) {
+ var abiInfo = {};
+ if (androidAbis.length > 1)
+ console.info("Found abi '" + androidAbis[a] + "'...");
+ abiInfo.androidAbi = androidAbis[a];
+ var allModules = qtProps.qtMajorVersion < 5
+ ? allQt4Modules(qtProps) : allQt5Modules(qtProps, androidAbis[a]);;
+ abiInfo.modules = {};
+ for (var i = 0; i < allModules.length; ++i) {
+ var module = allModules[i];
+ abiInfo.modules[module.qbsName] = module;
+ }
+ abiInfo.pluginsByType = {};
+ abiInfo.nonEssentialPlugins = [];
+ for (var moduleName in abiInfo.modules) {
+ var m = abiInfo.modules[moduleName];
+ if (m.isPlugin) {
+ if (!abiInfo.pluginsByType[m.pluginData.type])
+ abiInfo.pluginsByType[m.pluginData.type] = [];
+ abiInfo.pluginsByType[m.pluginData.type].push(m.name);
+ if (!m.pluginData.autoLoad)
+ abiInfo.nonEssentialPlugins.push(m.name);
+ }
+ }
+
+ result.abiInfos.push(abiInfo);
+ }
+ return result;
+}
+
+function configure(qmakeFilePaths) {
+ var result = [];
+ qmakeFilePaths = getQmakeFilePaths(qmakeFilePaths);
+ if (!qmakeFilePaths || qmakeFilePaths.length === 0)
+ return result;
+ for (var i = 0; i < qmakeFilePaths.length; ++i) {
+ var qtInfo = {};
+ try {
+ console.info("Getting info about Qt at '"
+ + FileInfo.toNativeSeparators(qmakeFilePaths[i]) + "'...");
+ qtInfo = getQtInfo(qmakeFilePaths[i]);
+ result.push(qtInfo);
+ } catch (e) {
+ console.warn("Error getting info about Qt for '"
+ + FileInfo.toNativeSeparators(qmakeFilePaths[i]) + "': " + e);
+ throw e;
+ }
+ }
+ return result;
+}