aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--share/qbs/imports/qbs/Probes/ClangClProbe.qbs88
-rw-r--r--share/qbs/modules/cpp/CppModule.qbs72
-rw-r--r--share/qbs/modules/cpp/msvc.js28
-rw-r--r--share/qbs/modules/cpp/windows-clang-cl.qbs84
-rw-r--r--share/qbs/modules/cpp/windows-msvc-base.qbs372
-rw-r--r--share/qbs/modules/cpp/windows-msvc.qbs344
-rw-r--r--src/app/qbs-setup-toolchains/clangclprobe.cpp172
-rw-r--r--src/app/qbs-setup-toolchains/clangclprobe.h55
-rw-r--r--src/app/qbs-setup-toolchains/msvcprobe.cpp33
-rw-r--r--src/app/qbs-setup-toolchains/msvcprobe.h12
-rw-r--r--src/app/qbs-setup-toolchains/probe.cpp8
-rw-r--r--src/app/qbs-setup-toolchains/probe.h2
-rw-r--r--src/app/qbs-setup-toolchains/qbs-setup-toolchains.pro2
-rw-r--r--src/app/qbs-setup-toolchains/qbs-setup-toolchains.qbs2
-rw-r--r--src/lib/corelib/jsextensions/utilitiesextension.cpp97
-rw-r--r--src/lib/corelib/tools/hostosinfo.h9
-rw-r--r--src/lib/corelib/tools/msvcinfo.cpp80
-rw-r--r--src/lib/corelib/tools/msvcinfo.h9
-rw-r--r--src/lib/corelib/tools/vsenvironmentdetector.cpp13
-rw-r--r--src/lib/corelib/tools/vsenvironmentdetector.h3
-rw-r--r--tests/auto/api/testdata/app-without-sources/app-without-sources.qbs1
-rw-r--r--tests/auto/api/testdata/precompiled-header-dynamic/autogen.h.in5
-rw-r--r--tests/auto/blackbox/testdata/cxx-language-version/cxx-language-version.qbs5
-rw-r--r--tests/auto/blackbox/testdata/enableRtti/main.cpp4
-rw-r--r--tests/auto/blackbox/testdata/minimumSystemVersion/main.cpp4
-rw-r--r--tests/auto/blackbox/testdata/no-exported-symbols/no-exported-symbols.qbs2
-rw-r--r--tests/auto/blackbox/tst_blackbox.cpp2
27 files changed, 1088 insertions, 420 deletions
diff --git a/share/qbs/imports/qbs/Probes/ClangClProbe.qbs b/share/qbs/imports/qbs/Probes/ClangClProbe.qbs
new file mode 100644
index 000000000..c7687f0e9
--- /dev/null
+++ b/share/qbs/imports/qbs/Probes/ClangClProbe.qbs
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Ivan Komissarov (abbapoh@gmail.com)
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+import qbs.File
+import qbs.FileInfo
+import qbs.ModUtils
+import qbs.Utilities
+import "../../../modules/cpp/gcc.js" as Gcc
+
+PathProbe {
+ // Inputs
+ property string compilerFilePath
+ property string vcvarsallFilePath
+ property stringList enableDefinesByLanguage
+ property string architecture
+ property string _nullDevice: qbs.nullDevice
+ property string _pathListSeparator: qbs.pathListSeparator
+
+ // Outputs
+ property int versionMajor
+ property int versionMinor
+ property int versionPatch
+ property stringList includePaths
+ property var buildEnv
+ property var compilerDefinesByLanguage
+
+ configure: {
+ var languages = enableDefinesByLanguage;
+ if (!languages || languages.length === 0)
+ languages = ["c"];
+
+ var info = languages.contains("c")
+ ? Utilities.clangClCompilerInfo(compilerFilePath, architecture, vcvarsallFilePath, "c") : {};
+ var infoCpp = languages.contains("cpp")
+ ? Utilities.clangClCompilerInfo(compilerFilePath, architecture, vcvarsallFilePath, "cpp") : {};
+ found = (!languages.contains("c") ||
+ (!!info && !!info.macros && !!info.buildEnvironment))
+ && (!languages.contains("cpp") ||
+ (!!infoCpp && !!infoCpp.macros && !!infoCpp.buildEnvironment));
+
+ compilerDefinesByLanguage = {
+ "c": info.macros,
+ "cpp": infoCpp.macros,
+ };
+
+ var macros = info.macros || infoCpp.macros;
+
+ versionMajor = parseInt(macros["__clang_major__"], 10);
+ versionMinor = parseInt(macros["__clang_minor__"], 10);
+ versionPatch = parseInt(macros["__clang_patchlevel__"], 10);
+
+ buildEnv = info.buildEnvironment || infoCpp.buildEnvironment;
+ // clang-cl is just a wrapper around clang.exe, so the includes *should be* the same
+ var clangPath = FileInfo.joinPaths(FileInfo.path(compilerFilePath), "clang.exe");
+
+ var defaultPaths = Gcc.dumpDefaultPaths(buildEnv, clangPath,
+ [], _nullDevice,
+ _pathListSeparator, "", "");
+ includePaths = defaultPaths.includePaths;
+ }
+}
diff --git a/share/qbs/modules/cpp/CppModule.qbs b/share/qbs/modules/cpp/CppModule.qbs
index 01b0f8af9..35a5de4f0 100644
--- a/share/qbs/modules/cpp/CppModule.qbs
+++ b/share/qbs/modules/cpp/CppModule.qbs
@@ -454,42 +454,48 @@ Module {
fileTags: ["hpp"]
}
- validate: {
- var validator = new ModUtils.PropertyValidator("cpp");
- validator.setRequiredProperty("architecture", architecture,
- "you might want to re-run 'qbs-setup-toolchains'");
- validator.addCustomValidator("architecture", architecture, function (value) {
- return !architecture || architecture === Utilities.canonicalArchitecture(architecture);
- }, "'" + architecture + "' is invalid. You must use the canonical name '" +
- Utilities.canonicalArchitecture(architecture) + "'");
- validator.setRequiredProperty("endianness", endianness);
- validator.setRequiredProperty("compilerDefinesByLanguage", compilerDefinesByLanguage);
- validator.setRequiredProperty("compilerVersion", compilerVersion);
- validator.setRequiredProperty("compilerVersionMajor", compilerVersionMajor);
- validator.setRequiredProperty("compilerVersionMinor", compilerVersionMinor);
- validator.setRequiredProperty("compilerVersionPatch", compilerVersionPatch);
- validator.addVersionValidator("compilerVersion", compilerVersion, 3, 3);
- validator.addRangeValidator("compilerVersionMajor", compilerVersionMajor, 1);
- validator.addRangeValidator("compilerVersionMinor", compilerVersionMinor, 0);
- validator.addRangeValidator("compilerVersionPatch", compilerVersionPatch, 0);
- if (minimumWindowsVersion) {
- validator.addVersionValidator("minimumWindowsVersion", minimumWindowsVersion, 2, 2);
- validator.addCustomValidator("minimumWindowsVersion", minimumWindowsVersion, function (v) {
- return !v || v === WindowsUtils.canonicalizeVersion(v);
- }, "'" + minimumWindowsVersion + "' is invalid. Did you mean '" +
- WindowsUtils.canonicalizeVersion(minimumWindowsVersion) + "'?");
- }
- validator.validate();
-
- if (minimumWindowsVersion && !WindowsUtils.isValidWindowsVersion(minimumWindowsVersion)) {
- console.warn("Unknown Windows version '" + minimumWindowsVersion
- + "'; expected one of: "
- + WindowsUtils.knownWindowsVersions().map(function (a) {
- return '"' + a + '"'; }).join(", ")
- + ". See https://docs.microsoft.com/en-us/windows/desktop/SysInfo/operating-system-version");
+ property var validateFunc: {
+ return function() {
+ var validator = new ModUtils.PropertyValidator("cpp");
+ validator.setRequiredProperty("architecture", architecture,
+ "you might want to re-run 'qbs-setup-toolchains'");
+ validator.addCustomValidator("architecture", architecture, function (value) {
+ return !architecture || architecture === Utilities.canonicalArchitecture(architecture);
+ }, "'" + architecture + "' is invalid. You must use the canonical name '" +
+ Utilities.canonicalArchitecture(architecture) + "'");
+ validator.setRequiredProperty("endianness", endianness);
+ validator.setRequiredProperty("compilerDefinesByLanguage", compilerDefinesByLanguage);
+ validator.setRequiredProperty("compilerVersion", compilerVersion);
+ validator.setRequiredProperty("compilerVersionMajor", compilerVersionMajor);
+ validator.setRequiredProperty("compilerVersionMinor", compilerVersionMinor);
+ validator.setRequiredProperty("compilerVersionPatch", compilerVersionPatch);
+ validator.addVersionValidator("compilerVersion", compilerVersion, 3, 3);
+ validator.addRangeValidator("compilerVersionMajor", compilerVersionMajor, 1);
+ validator.addRangeValidator("compilerVersionMinor", compilerVersionMinor, 0);
+ validator.addRangeValidator("compilerVersionPatch", compilerVersionPatch, 0);
+ if (minimumWindowsVersion) {
+ validator.addVersionValidator("minimumWindowsVersion", minimumWindowsVersion, 2, 2);
+ validator.addCustomValidator("minimumWindowsVersion", minimumWindowsVersion, function (v) {
+ return !v || v === WindowsUtils.canonicalizeVersion(v);
+ }, "'" + minimumWindowsVersion + "' is invalid. Did you mean '" +
+ WindowsUtils.canonicalizeVersion(minimumWindowsVersion) + "'?");
+ }
+ validator.validate();
+
+ if (minimumWindowsVersion && !WindowsUtils.isValidWindowsVersion(minimumWindowsVersion)) {
+ console.warn("Unknown Windows version '" + minimumWindowsVersion
+ + "'; expected one of: "
+ + WindowsUtils.knownWindowsVersions().map(function (a) {
+ return '"' + a + '"'; }).join(", ")
+ + ". See https://docs.microsoft.com/en-us/windows/desktop/SysInfo/operating-system-version");
+ }
}
}
+ validate: {
+ return validateFunc();
+ }
+
setupRunEnvironment: {
SetupRunEnv.setupRunEnvironment(product, config);
}
diff --git a/share/qbs/modules/cpp/msvc.js b/share/qbs/modules/cpp/msvc.js
index 1864c40e1..5da2ad0cf 100644
--- a/share/qbs/modules/cpp/msvc.js
+++ b/share/qbs/modules/cpp/msvc.js
@@ -62,7 +62,8 @@ function hasCxx17Option(input)
{
// Probably this is not the earliest version to support the flag, but we have tested this one
// and it's a pain to find out the exact minimum.
- return Utilities.versionCompare(input.cpp.compilerVersion, "19.12.25831") >= 0;
+ return Utilities.versionCompare(input.cpp.compilerVersion, "19.12.25831") >= 0
+ || (input.qbs.toolchain.contains("clang-cl") && input.cpp.compilerVersionMajor >= 7);
}
function addLanguageVersionFlag(input, args) {
@@ -72,7 +73,9 @@ function addLanguageVersionFlag(input, args) {
return;
// Visual C++ 2013, Update 3
- var hasStdOption = Utilities.versionCompare(input.cpp.compilerVersion, "18.00.30723") >= 0;
+ var hasStdOption = Utilities.versionCompare(input.cpp.compilerVersion, "18.00.30723") >= 0
+ // or clang-cl
+ || input.qbs.toolchain.contains("clang-cl");
if (!hasStdOption)
return;
@@ -210,10 +213,20 @@ function prepareCompiler(project, product, inputs, outputs, input, output, expli
var pchInputs = explicitlyDependsOn[tag + "_pch"];
if (pchOutput) {
// create PCH
- args.push("/Yc");
- args.push("/Fp" + FileInfo.toWindowsSeparators(pchOutput.filePath));
- args.push("/Fo" + FileInfo.toWindowsSeparators(objOutput.filePath));
- args.push(FileInfo.toWindowsSeparators(input.filePath));
+ if (input.qbs.toolchain.contains("clang-cl")) {
+ // clang-cl does not support /Yc flag without filename
+ args.push("/Yc" + FileInfo.toWindowsSeparators(input.filePath));
+ // clang-cl complains when pch file is not included
+ args.push("/FI" + FileInfo.toWindowsSeparators(input.filePath));
+ args.push("/Fp" + FileInfo.toWindowsSeparators(pchOutput.filePath));
+ args.push("/Fo" + FileInfo.toWindowsSeparators(objOutput.filePath));
+ } else { // real msvc
+ args.push("/Yc");
+ args.push("/Fp" + FileInfo.toWindowsSeparators(pchOutput.filePath));
+ args.push("/Fo" + FileInfo.toWindowsSeparators(objOutput.filePath));
+ args.push(FileInfo.toWindowsSeparators(input.filePath));
+ }
+
} else if (pchInputs && pchInputs.length === 1
&& ModUtils.moduleProperty(input, "usePrecompiledHeader", tag)) {
// use PCH
@@ -399,7 +412,8 @@ function prepareLinker(project, product, inputs, outputs, input, output) {
'subsystem');
if (subsystemVersion) {
subsystemSwitch += ',' + subsystemVersion;
- args.push('/OSVERSION:' + subsystemVersion);
+ if (product.cpp.linkerName !== "lld-link.exe") // llvm linker does not support /OSVERSION
+ args.push('/OSVERSION:' + subsystemVersion);
}
}
diff --git a/share/qbs/modules/cpp/windows-clang-cl.qbs b/share/qbs/modules/cpp/windows-clang-cl.qbs
new file mode 100644
index 000000000..1b2833060
--- /dev/null
+++ b/share/qbs/modules/cpp/windows-clang-cl.qbs
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Ivan Komissarov (abbapoh@gmail.com)
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+import qbs
+import qbs.ModUtils
+import qbs.Probes
+import qbs.FileInfo
+import 'windows-msvc-base.qbs' as MsvcBaseModule
+
+MsvcBaseModule {
+ condition: qbs.hostOS.contains('windows') &&
+ qbs.targetOS.contains('windows') &&
+ qbs.toolchain && qbs.toolchain.contains('clang-cl')
+ priority: 100
+
+ Probes.BinaryProbe {
+ id: clangPathProbe
+ condition: !toolchainInstallPath && !_skipAllChecks
+ names: ["clang-cl"]
+ }
+
+ Probes.ClangClProbe {
+ id: clangClProbe
+ condition: !_skipAllChecks
+ compilerFilePath: compilerPath
+ vcvarsallFilePath: vcvarsallPath
+ enableDefinesByLanguage: enableCompilerDefinesByLanguage
+ architecture: qbs.architecture
+ }
+
+ compilerVersionMajor: clangClProbe.versionMajor
+ compilerVersionMinor: clangClProbe.versionMinor
+ compilerVersionPatch: clangClProbe.versionPatch
+ compilerIncludePaths: clangClProbe.includePaths
+ compilerDefinesByLanguage: clangClProbe.compilerDefinesByLanguage
+
+ toolchainInstallPath: clangPathProbe.found ? clangPathProbe.path
+ : undefined
+ buildEnv: clangClProbe.buildEnv
+
+ property string vcvarsallPath
+
+ compilerName: "clang-cl.exe"
+ linkerName: "lld-link.exe"
+ linkerPath: FileInfo.joinPaths(toolchainInstallPath, linkerName)
+
+ validateFunc: {
+ return function() {
+ if (_skipAllChecks)
+ return;
+ var validator = new ModUtils.PropertyValidator("cpp");
+ validator.setRequiredProperty("vcvarsallPath", vcvarsallPath);
+ validator.validate();
+ base();
+ }
+ }
+}
diff --git a/share/qbs/modules/cpp/windows-msvc-base.qbs b/share/qbs/modules/cpp/windows-msvc-base.qbs
new file mode 100644
index 000000000..d36daa99f
--- /dev/null
+++ b/share/qbs/modules/cpp/windows-msvc-base.qbs
@@ -0,0 +1,372 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+import qbs.File
+import qbs.FileInfo
+import qbs.ModUtils
+import qbs.PathTools
+import qbs.Probes
+import qbs.Utilities
+import qbs.WindowsUtils
+import 'msvc.js' as MSVC
+
+CppModule {
+ condition: false
+
+ windowsApiCharacterSet: "unicode"
+ platformDefines: {
+ var defines = base.concat(WindowsUtils.characterSetDefines(windowsApiCharacterSet))
+ .concat("WIN32");
+ var def = WindowsUtils.winapiFamilyDefine(windowsApiFamily);
+ if (def)
+ defines.push("WINAPI_FAMILY=WINAPI_FAMILY_" + def);
+ (windowsApiAdditionalPartitions || []).map(function (name) {
+ defines.push("WINAPI_PARTITION_" + WindowsUtils.winapiPartitionDefine(name) + "=1");
+ });
+ return defines;
+ }
+ platformCommonCompilerFlags: {
+ var flags = base;
+ if (compilerVersionMajor >= 18) // 2013
+ flags.push("/FS");
+ return flags;
+ }
+ warningLevel: "default"
+ compilerName: "cl.exe"
+ compilerPath: FileInfo.joinPaths(toolchainInstallPath, compilerName)
+ assemblerName: {
+ switch (qbs.architecture) {
+ case "armv7":
+ return "armasm.exe";
+ case "arm64":
+ return "armasm64.exe";
+ case "ia64":
+ return "ias.exe";
+ case "x86":
+ return "ml.exe";
+ case "x86_64":
+ return "ml64.exe";
+ }
+ }
+
+ linkerName: "link.exe"
+ runtimeLibrary: "dynamic"
+ separateDebugInformation: true
+
+ property bool generateManifestFile: true
+ property string toolchainInstallPath
+
+ architecture: qbs.architecture
+ endianness: "little"
+ staticLibrarySuffix: ".lib"
+ dynamicLibrarySuffix: ".dll"
+ executableSuffix: ".exe"
+ debugInfoSuffix: ".pdb"
+ imageFormat: "pe"
+ Properties {
+ condition: product.multiplexByQbsProperties.contains("buildVariants")
+ && qbs.buildVariants && qbs.buildVariants.length > 1
+ && qbs.buildVariant !== "release"
+ && product.type.containsAny(["staticlibrary", "dynamiclibrary"])
+ variantSuffix: "d"
+ }
+
+ property var buildEnv
+
+ setupBuildEnvironment: {
+ for (var key in product.cpp.buildEnv) {
+ var v = new ModUtils.EnvironmentVariable(key, ';');
+ v.prepend(product.cpp.buildEnv[key]);
+ v.set();
+ }
+ }
+
+ Rule {
+ condition: useCPrecompiledHeader
+ inputs: ["c_pch_src"]
+ auxiliaryInputs: ["hpp"]
+ Artifact {
+ fileTags: ['obj']
+ filePath: Utilities.getHash(input.completeBaseName) + '_c.obj'
+ }
+ Artifact {
+ fileTags: ['c_pch']
+ filePath: product.name + '_c.pch'
+ }
+ prepare: {
+ return MSVC.prepareCompiler.apply(MSVC, arguments);
+ }
+ }
+
+ Rule {
+ condition: useCxxPrecompiledHeader
+ inputs: ["cpp_pch_src"]
+ explicitlyDependsOn: ["c_pch"] // to prevent vc--0.pdb conflict
+ auxiliaryInputs: ["hpp"]
+ Artifact {
+ fileTags: ['obj']
+ filePath: Utilities.getHash(input.completeBaseName) + '_cpp.obj'
+ }
+ Artifact {
+ fileTags: ['cpp_pch']
+ filePath: product.name + '_cpp.pch'
+ }
+ prepare: {
+ return MSVC.prepareCompiler.apply(MSVC, arguments);
+ }
+ }
+
+ Rule {
+ name: "compiler"
+ inputs: ["cpp", "c"]
+ auxiliaryInputs: ["hpp"]
+ explicitlyDependsOn: ["c_pch", "cpp_pch"]
+
+ outputFileTags: ["obj", "intermediate_obj"]
+ outputArtifacts: {
+ var tags = input.fileTags.contains("cpp_intermediate_object")
+ ? ["intermediate_obj"]
+ : ["obj"];
+ return [{
+ fileTags: tags,
+ filePath: Utilities.getHash(input.baseDir) + "/" + input.fileName + ".obj"
+ }];
+ }
+
+ prepare: {
+ return MSVC.prepareCompiler.apply(MSVC, arguments);
+ }
+ }
+
+ FileTagger {
+ patterns: ["*.manifest"]
+ fileTags: ["native.pe.manifest"]
+ }
+
+ Rule {
+ name: "applicationLinker"
+ multiplex: true
+ inputs: ['obj', 'native.pe.manifest']
+ inputsFromDependencies: ['staticlibrary', 'dynamiclibrary_import', "debuginfo_app"]
+
+ outputFileTags: ["application", "debuginfo_app"]
+ outputArtifacts: {
+ var app = {
+ fileTags: ["application"],
+ filePath: FileInfo.joinPaths(
+ product.destinationDirectory,
+ PathTools.applicationFilePath(product))
+ };
+ var artifacts = [app];
+ if (product.cpp.debugInformation && product.cpp.separateDebugInformation) {
+ artifacts.push({
+ fileTags: ["debuginfo_app"],
+ filePath: app.filePath.substr(0, app.filePath.length - 4)
+ + product.cpp.debugInfoSuffix
+ });
+ }
+ return artifacts;
+ }
+
+ prepare: {
+ return MSVC.prepareLinker.apply(MSVC, arguments);
+ }
+ }
+
+ Rule {
+ name: "dynamicLibraryLinker"
+ multiplex: true
+ inputs: ['obj', 'native.pe.manifest']
+ inputsFromDependencies: ['staticlibrary', 'dynamiclibrary_import', "debuginfo_dll"]
+
+ outputFileTags: ["dynamiclibrary", "dynamiclibrary_import", "debuginfo_dll"]
+ outputArtifacts: {
+ var artifacts = [
+ {
+ fileTags: ["dynamiclibrary"],
+ filePath: product.destinationDirectory + "/" + PathTools.dynamicLibraryFilePath(product)
+ },
+ {
+ fileTags: ["dynamiclibrary_import"],
+ filePath: product.destinationDirectory + "/" + PathTools.importLibraryFilePath(product),
+ alwaysUpdated: false
+ }
+ ];
+ if (product.cpp.debugInformation && product.cpp.separateDebugInformation) {
+ var lib = artifacts[0];
+ artifacts.push({
+ fileTags: ["debuginfo_dll"],
+ filePath: lib.filePath.substr(0, lib.filePath.length - 4)
+ + product.cpp.debugInfoSuffix
+ });
+ }
+ return artifacts;
+ }
+
+ prepare: {
+ return MSVC.prepareLinker.apply(MSVC, arguments);
+ }
+ }
+
+ Rule {
+ name: "libtool"
+ multiplex: true
+ inputs: ["obj"]
+ inputsFromDependencies: ["staticlibrary", "dynamiclibrary_import"]
+ outputFileTags: ["staticlibrary", "debuginfo_cl"]
+ outputArtifacts: {
+ var artifacts = [
+ {
+ fileTags: ["staticlibrary"],
+ filePath: FileInfo.joinPaths(product.destinationDirectory,
+ PathTools.staticLibraryFilePath(product))
+ }
+ ];
+ if (product.cpp.debugInformation && product.cpp.separateDebugInformation) {
+ artifacts.push({
+ fileTags: ["debuginfo_cl"],
+ filePath: product.targetName + ".cl" + product.cpp.debugInfoSuffix
+ });
+ }
+ return artifacts;
+ }
+ prepare: {
+ var args = ['/nologo']
+ var lib = outputs["staticlibrary"][0];
+ var nativeOutputFileName = FileInfo.toWindowsSeparators(lib.filePath)
+ args.push('/OUT:' + nativeOutputFileName)
+ for (var i in inputs.obj) {
+ var fileName = FileInfo.toWindowsSeparators(inputs.obj[i].filePath)
+ args.push(fileName)
+ }
+ var cmd = new Command("lib.exe", args);
+ cmd.description = 'creating ' + lib.fileName;
+ cmd.highlight = 'linker';
+ cmd.jobPool = "linker";
+ cmd.workingDirectory = FileInfo.path(lib.filePath)
+ cmd.responseFileUsagePrefix = '@';
+ return cmd;
+ }
+ }
+
+ FileTagger {
+ patterns: ["*.rc"]
+ fileTags: ["rc"]
+ }
+
+ Rule {
+ inputs: ["rc"]
+ auxiliaryInputs: ["hpp"]
+
+ Artifact {
+ filePath: Utilities.getHash(input.baseDir) + "/" + input.completeBaseName + ".res"
+ fileTags: ["obj"]
+ }
+
+ prepare: {
+ var platformDefines = input.cpp.platformDefines;
+ var defines = input.cpp.defines;
+ var includePaths = input.cpp.includePaths;
+ var systemIncludePaths = input.cpp.systemIncludePaths;
+ var args = [];
+ var i;
+ var hasNoLogo = product.cpp.compilerVersionMajor >= 16; // 2010
+ if (hasNoLogo)
+ args.push("/nologo");
+
+ for (i in platformDefines) {
+ args.push('/d');
+ args.push(platformDefines[i]);
+ }
+ for (i in defines) {
+ args.push('/d');
+ args.push(defines[i]);
+ }
+ for (i in includePaths) {
+ args.push('/i');
+ args.push(includePaths[i]);
+ }
+ for (i in systemIncludePaths) {
+ args.push('/i');
+ args.push(systemIncludePaths[i]);
+ }
+
+ args = args.concat(['/fo', output.filePath, input.filePath]);
+ var cmd = new Command('rc', args);
+ cmd.description = 'compiling ' + input.fileName;
+ cmd.highlight = 'compiler';
+ cmd.jobPool = "compiler";
+
+ if (!hasNoLogo) {
+ // Remove the first two lines of stdout. That's the logo.
+ cmd.stdoutFilterFunction = function(output) {
+ var idx = 0;
+ for (var i = 0; i < 3; ++i)
+ idx = output.indexOf('\n', idx + 1);
+ return output.substr(idx + 1);
+ }
+ }
+
+ return cmd;
+ }
+ }
+
+ FileTagger {
+ patterns: "*.asm"
+ fileTags: ["asm"]
+ }
+
+ Rule {
+ inputs: ["asm"]
+ Artifact {
+ filePath: Utilities.getHash(input.baseDir) + "/" + input.completeBaseName + ".obj"
+ fileTags: ["obj"]
+ }
+ prepare: {
+ var args = ["/nologo", "/c",
+ "/Fo" + FileInfo.toWindowsSeparators(output.filePath),
+ FileInfo.toWindowsSeparators(input.filePath)];
+ if (product.cpp.debugInformation)
+ args.push("/Zi");
+ args = args.concat(ModUtils.moduleProperty(input, 'platformFlags', 'asm'),
+ ModUtils.moduleProperty(input, 'flags', 'asm'));
+ var cmd = new Command(product.cpp.assemblerPath, args);
+ cmd.description = "assembling " + input.fileName;
+ cmd.jobPool = "assembler";
+ cmd.inputFileName = input.fileName;
+ cmd.stdoutFilterFunction = function(output) {
+ var lines = output.split("\r\n").filter(function (s) {
+ return !s.endsWith(inputFileName); });
+ return lines.join("\r\n");
+ };
+ return cmd;
+ }
+ }
+}
diff --git a/share/qbs/modules/cpp/windows-msvc.qbs b/share/qbs/modules/cpp/windows-msvc.qbs
index 8dd6dd2c0..59032d28a 100644
--- a/share/qbs/modules/cpp/windows-msvc.qbs
+++ b/share/qbs/modules/cpp/windows-msvc.qbs
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
+** Copyright (C) 2019 Ivan Komissarov (abbapoh@gmail.com)
** Contact: http://www.qt.io/licensing
**
** This file is part of Qbs.
@@ -28,19 +29,14 @@
**
****************************************************************************/
-import qbs.File
-import qbs.FileInfo
-import qbs.ModUtils
-import qbs.PathTools
import qbs.Probes
-import qbs.Utilities
-import qbs.WindowsUtils
-import 'msvc.js' as MSVC
+import "windows-msvc-base.qbs" as MsvcBaseModule
-CppModule {
+MsvcBaseModule {
condition: qbs.hostOS.contains('windows') &&
qbs.targetOS.contains('windows') &&
qbs.toolchain && qbs.toolchain.contains('msvc')
+ priority: 50
Probes.BinaryProbe {
id: compilerPathProbe
@@ -62,335 +58,9 @@ CppModule {
compilerVersionMinor: msvcProbe.versionMinor
compilerVersionPatch: msvcProbe.versionPatch
compilerIncludePaths: msvcProbe.includePaths
-
- windowsApiCharacterSet: "unicode"
- platformDefines: {
- var defines = base.concat(WindowsUtils.characterSetDefines(windowsApiCharacterSet))
- .concat("WIN32");
- var def = WindowsUtils.winapiFamilyDefine(windowsApiFamily);
- if (def)
- defines.push("WINAPI_FAMILY=WINAPI_FAMILY_" + def);
- (windowsApiAdditionalPartitions || []).map(function (name) {
- defines.push("WINAPI_PARTITION_" + WindowsUtils.winapiPartitionDefine(name) + "=1");
- });
- return defines;
- }
- platformCommonCompilerFlags: {
- var flags = base;
- if (compilerVersionMajor >= 18) // 2013
- flags.push("/FS");
- return flags;
- }
compilerDefinesByLanguage: msvcProbe.compilerDefinesByLanguage
- warningLevel: "default"
- compilerName: "cl.exe"
- compilerPath: FileInfo.joinPaths(toolchainInstallPath, compilerName)
- assemblerName: {
- switch (qbs.architecture) {
- case "armv7":
- return "armasm.exe";
- case "arm64":
- return "armasm64.exe";
- case "ia64":
- return "ias.exe";
- case "x86":
- return "ml.exe";
- case "x86_64":
- return "ml64.exe";
- }
- }
-
- linkerName: "link.exe"
- runtimeLibrary: "dynamic"
- separateDebugInformation: true
-
- property bool generateManifestFile: true
- property string toolchainInstallPath: compilerPathProbe.found ? compilerPathProbe.path
- : undefined
- architecture: qbs.architecture
- endianness: "little"
- staticLibrarySuffix: ".lib"
- dynamicLibrarySuffix: ".dll"
- executableSuffix: ".exe"
- debugInfoSuffix: ".pdb"
- imageFormat: "pe"
- Properties {
- condition: product.multiplexByQbsProperties.contains("buildVariants")
- && qbs.buildVariants && qbs.buildVariants.length > 1
- && qbs.buildVariant !== "release"
- && product.type.containsAny(["staticlibrary", "dynamiclibrary"])
- variantSuffix: "d"
- }
-
- property var buildEnv: msvcProbe.buildEnv
-
- setupBuildEnvironment: {
- for (var key in product.cpp.buildEnv) {
- var v = new ModUtils.EnvironmentVariable(key, ';');
- v.prepend(product.cpp.buildEnv[key]);
- v.set();
- }
- }
-
- Rule {
- condition: useCPrecompiledHeader
- inputs: ["c_pch_src"]
- auxiliaryInputs: ["hpp"]
- Artifact {
- fileTags: ['obj']
- filePath: Utilities.getHash(input.completeBaseName) + '_c.obj'
- }
- Artifact {
- fileTags: ['c_pch']
- filePath: product.name + '_c.pch'
- }
- prepare: {
- return MSVC.prepareCompiler.apply(MSVC, arguments);
- }
- }
-
- Rule {
- condition: useCxxPrecompiledHeader
- inputs: ["cpp_pch_src"]
- explicitlyDependsOn: ["c_pch"] // to prevent vc--0.pdb conflict
- auxiliaryInputs: ["hpp"]
- Artifact {
- fileTags: ['obj']
- filePath: Utilities.getHash(input.completeBaseName) + '_cpp.obj'
- }
- Artifact {
- fileTags: ['cpp_pch']
- filePath: product.name + '_cpp.pch'
- }
- prepare: {
- return MSVC.prepareCompiler.apply(MSVC, arguments);
- }
- }
-
- Rule {
- name: "compiler"
- inputs: ["cpp", "c"]
- auxiliaryInputs: ["hpp"]
- explicitlyDependsOn: ["c_pch", "cpp_pch"]
-
- outputFileTags: ["obj", "intermediate_obj"]
- outputArtifacts: {
- var tags = input.fileTags.contains("cpp_intermediate_object")
- ? ["intermediate_obj"]
- : ["obj"];
- return [{
- fileTags: tags,
- filePath: Utilities.getHash(input.baseDir) + "/" + input.fileName + ".obj"
- }];
- }
-
- prepare: {
- return MSVC.prepareCompiler.apply(MSVC, arguments);
- }
- }
-
- FileTagger {
- patterns: ["*.manifest"]
- fileTags: ["native.pe.manifest"]
- }
-
- Rule {
- name: "applicationLinker"
- multiplex: true
- inputs: ['obj', 'native.pe.manifest']
- inputsFromDependencies: ['staticlibrary', 'dynamiclibrary_import', "debuginfo_app"]
-
- outputFileTags: ["application", "debuginfo_app"]
- outputArtifacts: {
- var app = {
- fileTags: ["application"],
- filePath: FileInfo.joinPaths(
- product.destinationDirectory,
- PathTools.applicationFilePath(product))
- };
- var artifacts = [app];
- if (product.cpp.debugInformation && product.cpp.separateDebugInformation) {
- artifacts.push({
- fileTags: ["debuginfo_app"],
- filePath: app.filePath.substr(0, app.filePath.length - 4)
- + product.cpp.debugInfoSuffix
- });
- }
- return artifacts;
- }
- prepare: {
- return MSVC.prepareLinker.apply(MSVC, arguments);
- }
- }
-
- Rule {
- name: "dynamicLibraryLinker"
- multiplex: true
- inputs: ['obj', 'native.pe.manifest']
- inputsFromDependencies: ['staticlibrary', 'dynamiclibrary_import', "debuginfo_dll"]
-
- outputFileTags: ["dynamiclibrary", "dynamiclibrary_import", "debuginfo_dll"]
- outputArtifacts: {
- var artifacts = [
- {
- fileTags: ["dynamiclibrary"],
- filePath: product.destinationDirectory + "/" + PathTools.dynamicLibraryFilePath(product)
- },
- {
- fileTags: ["dynamiclibrary_import"],
- filePath: product.destinationDirectory + "/" + PathTools.importLibraryFilePath(product),
- alwaysUpdated: false
- }
- ];
- if (product.cpp.debugInformation && product.cpp.separateDebugInformation) {
- var lib = artifacts[0];
- artifacts.push({
- fileTags: ["debuginfo_dll"],
- filePath: lib.filePath.substr(0, lib.filePath.length - 4)
- + product.cpp.debugInfoSuffix
- });
- }
- return artifacts;
- }
-
- prepare: {
- return MSVC.prepareLinker.apply(MSVC, arguments);
- }
- }
-
- Rule {
- name: "libtool"
- multiplex: true
- inputs: ["obj"]
- inputsFromDependencies: ["staticlibrary", "dynamiclibrary_import"]
- outputFileTags: ["staticlibrary", "debuginfo_cl"]
- outputArtifacts: {
- var artifacts = [
- {
- fileTags: ["staticlibrary"],
- filePath: FileInfo.joinPaths(product.destinationDirectory,
- PathTools.staticLibraryFilePath(product))
- }
- ];
- if (product.cpp.debugInformation && product.cpp.separateDebugInformation) {
- artifacts.push({
- fileTags: ["debuginfo_cl"],
- filePath: product.targetName + ".cl" + product.cpp.debugInfoSuffix
- });
- }
- return artifacts;
- }
- prepare: {
- var args = ['/nologo']
- var lib = outputs["staticlibrary"][0];
- var nativeOutputFileName = FileInfo.toWindowsSeparators(lib.filePath)
- args.push('/OUT:' + nativeOutputFileName)
- for (var i in inputs.obj) {
- var fileName = FileInfo.toWindowsSeparators(inputs.obj[i].filePath)
- args.push(fileName)
- }
- var cmd = new Command("lib.exe", args);
- cmd.description = 'creating ' + lib.fileName;
- cmd.highlight = 'linker';
- cmd.jobPool = "linker";
- cmd.workingDirectory = FileInfo.path(lib.filePath)
- cmd.responseFileUsagePrefix = '@';
- return cmd;
- }
- }
-
- FileTagger {
- patterns: ["*.rc"]
- fileTags: ["rc"]
- }
-
- Rule {
- inputs: ["rc"]
- auxiliaryInputs: ["hpp"]
-
- Artifact {
- filePath: Utilities.getHash(input.baseDir) + "/" + input.completeBaseName + ".res"
- fileTags: ["obj"]
- }
-
- prepare: {
- var platformDefines = input.cpp.platformDefines;
- var defines = input.cpp.defines;
- var includePaths = input.cpp.includePaths;
- var systemIncludePaths = input.cpp.systemIncludePaths;
- var args = [];
- var i;
- var hasNoLogo = product.cpp.compilerVersionMajor >= 16; // 2010
- if (hasNoLogo)
- args.push("/nologo");
-
- for (i in platformDefines) {
- args.push('/d');
- args.push(platformDefines[i]);
- }
- for (i in defines) {
- args.push('/d');
- args.push(defines[i]);
- }
- for (i in includePaths) {
- args.push('/i');
- args.push(includePaths[i]);
- }
- for (i in systemIncludePaths) {
- args.push('/i');
- args.push(systemIncludePaths[i]);
- }
-
- args = args.concat(['/fo', output.filePath, input.filePath]);
- var cmd = new Command('rc', args);
- cmd.description = 'compiling ' + input.fileName;
- cmd.highlight = 'compiler';
- cmd.jobPool = "compiler";
-
- if (!hasNoLogo) {
- // Remove the first two lines of stdout. That's the logo.
- cmd.stdoutFilterFunction = function(output) {
- var idx = 0;
- for (var i = 0; i < 3; ++i)
- idx = output.indexOf('\n', idx + 1);
- return output.substr(idx + 1);
- }
- }
-
- return cmd;
- }
- }
-
- FileTagger {
- patterns: "*.asm"
- fileTags: ["asm"]
- }
-
- Rule {
- inputs: ["asm"]
- Artifact {
- filePath: Utilities.getHash(input.baseDir) + "/" + input.completeBaseName + ".obj"
- fileTags: ["obj"]
- }
- prepare: {
- var args = ["/nologo", "/c",
- "/Fo" + FileInfo.toWindowsSeparators(output.filePath),
- FileInfo.toWindowsSeparators(input.filePath)];
- if (product.cpp.debugInformation)
- args.push("/Zi");
- args = args.concat(ModUtils.moduleProperty(input, 'platformFlags', 'asm'),
- ModUtils.moduleProperty(input, 'flags', 'asm'));
- var cmd = new Command(product.cpp.assemblerPath, args);
- cmd.description = "assembling " + input.fileName;
- cmd.jobPool = "assembler";
- cmd.inputFileName = input.fileName;
- cmd.stdoutFilterFunction = function(output) {
- var lines = output.split("\r\n").filter(function (s) {
- return !s.endsWith(inputFileName); });
- return lines.join("\r\n");
- };
- return cmd;
- }
- }
+ toolchainInstallPath: compilerPathProbe.found ? compilerPathProbe.path
+ : undefined
+ buildEnv: msvcProbe.buildEnv
}
diff --git a/src/app/qbs-setup-toolchains/clangclprobe.cpp b/src/app/qbs-setup-toolchains/clangclprobe.cpp
new file mode 100644
index 000000000..89075c5e8
--- /dev/null
+++ b/src/app/qbs-setup-toolchains/clangclprobe.cpp
@@ -0,0 +1,172 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Ivan Komissarov (abbapoh@gmail.com)
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "clangclprobe.h"
+#include "msvcprobe.h"
+#include "probe.h"
+
+#include "../shared/logging/consolelogger.h"
+
+#include <logging/translator.h>
+#include <tools/hostosinfo.h>
+#include <tools/profile.h>
+#include <tools/qttools.h>
+#include <tools/settings.h>
+
+#include <QtCore/qdir.h>
+#include <QtCore/qfileinfo.h>
+
+using qbs::Settings;
+using qbs::Profile;
+using qbs::Internal::HostOsInfo;
+
+using qbs::Internal::Tr;
+
+namespace {
+
+QString getToolchainInstallPath(const QString &compilerFilePath)
+{
+ return QFileInfo(compilerFilePath).path(); // 1 level up
+}
+
+Profile createProfileHelper(
+ Settings *settings,
+ const QString &profileName,
+ const QString &toolchainInstallPath,
+ const QString &vcvarsallPath,
+ const QString &architecture)
+{
+ Profile profile(profileName, settings);
+ profile.removeProfile();
+ profile.setValue(QStringLiteral("qbs.architecture"), architecture);
+ profile.setValue(
+ QStringLiteral("qbs.toolchain"),
+ QStringList{QStringLiteral("clang-cl"), QStringLiteral("msvc")});
+ profile.setValue(QStringLiteral("cpp.toolchainInstallPath"), toolchainInstallPath);
+ profile.setValue(QStringLiteral("cpp.vcvarsallPath"), vcvarsallPath);
+ qbsInfo() << Tr::tr("Profile '%1' created for '%2'.")
+ .arg(profile.name(), QDir::toNativeSeparators(toolchainInstallPath));
+ return profile;
+}
+
+std::vector<MSVCInstallInfo> compatibleMsvcs()
+{
+ auto msvcs = installedMSVCs();
+ auto filter = [](const MSVCInstallInfo &info)
+ {
+ const auto versions = info.version.split(QLatin1Char('.'));
+ if (versions.empty())
+ return true;
+ bool ok = false;
+ const int major = versions.at(0).toInt(&ok);
+ return !(ok && major >= 15); // support MSVC2017 and above
+ };
+ const auto it = std::remove_if(msvcs.begin(), msvcs.end(), filter);
+ msvcs.erase(it, msvcs.end());
+ for (const auto &msvc: msvcs) {
+ auto vcvarsallPath = msvc.findVcvarsallBat();
+ if (vcvarsallPath.isEmpty())
+ continue;
+ }
+ return msvcs;
+}
+
+QString findCompatibleVcsarsallBat()
+{
+ for (const auto &msvc: compatibleMsvcs()) {
+ const auto vcvarsallPath = msvc.findVcvarsallBat();
+ if (!vcvarsallPath.isEmpty())
+ return vcvarsallPath;
+ }
+ return {};
+}
+
+} // namespace
+
+void createClangClProfile(
+ const QString &profileName, const QString &compilerFilePath, Settings *settings)
+{
+ const auto compilerName = QStringLiteral("clang-cl");
+ const auto vcvarsallPath = findCompatibleVcsarsallBat();
+ if (vcvarsallPath.isEmpty()) {
+ qbsWarning()
+ << Tr::tr("%1 requires installed Visual Studio 2017 or newer, but none was found.")
+ .arg(compilerName);
+ return;
+ }
+
+ const auto toolchainInstallPath = getToolchainInstallPath(compilerFilePath);
+ const auto hostArch = QString::fromStdString(HostOsInfo::hostOSArchitecture());
+ createProfileHelper(settings, profileName, toolchainInstallPath, vcvarsallPath, hostArch);
+}
+
+/*!
+ \brief Creates a clang-cl profile based on auto-detected vsversion.
+ \internal
+*/
+void clangClProbe(Settings *settings, QList<Profile> &profiles)
+{
+ const auto compilerName = QStringLiteral("clang-cl");
+ qbsInfo() << Tr::tr("Trying to detect %1...").arg(compilerName);
+ const auto compilerFilePath = findExecutable(HostOsInfo::appendExecutableSuffix(compilerName));
+ if (compilerFilePath.isEmpty()) {
+ qbsInfo() << Tr::tr("%1 was not found.").arg(compilerName);
+ return;
+ }
+
+ const auto vcvarsallPath = findCompatibleVcsarsallBat();
+ if (vcvarsallPath.isEmpty()) {
+ qbsWarning()
+ << Tr::tr("%1 requires installed Visual Studio 2017 or newer, but none was found.")
+ .arg(compilerName);
+ return;
+ }
+
+ const QString architectures[] = {
+ QStringLiteral("x86_64"),
+ QStringLiteral("x86")
+ };
+ const auto toolchainInstallPath = getToolchainInstallPath(compilerFilePath);
+ for (const auto &arch: architectures) {
+ const auto profileName = QStringLiteral("clang-cl-%1").arg(arch);
+ auto profile = createProfileHelper(
+ settings, profileName, toolchainInstallPath, vcvarsallPath, arch);
+ profiles.push_back(std::move(profile));
+ }
+}
diff --git a/src/app/qbs-setup-toolchains/clangclprobe.h b/src/app/qbs-setup-toolchains/clangclprobe.h
new file mode 100644
index 000000000..1e7724fbf
--- /dev/null
+++ b/src/app/qbs-setup-toolchains/clangclprobe.h
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Ivan Komissarov (abbapoh@gmail.com)
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef CLANGCLPROBE_H
+#define CLANGCLPROBE_H
+
+#include <QtCore/qlist.h>
+
+namespace qbs {
+class Profile;
+class Settings;
+}
+
+void createClangClProfile(
+ const QString &profileName, const QString &compilerFilePath, qbs::Settings *settings);
+
+void clangClProbe(qbs::Settings *settings, QList<qbs::Profile> &profiles);
+
+#endif // CLANGCLPROBE_H
diff --git a/src/app/qbs-setup-toolchains/msvcprobe.cpp b/src/app/qbs-setup-toolchains/msvcprobe.cpp
index faacb4d09..d0b60a7fe 100644
--- a/src/app/qbs-setup-toolchains/msvcprobe.cpp
+++ b/src/app/qbs-setup-toolchains/msvcprobe.cpp
@@ -160,12 +160,6 @@ static QString wow6432Key()
#endif
}
-struct MSVCInstallInfo
-{
- QString version;
- QString installDir;
-};
-
static QString vswhereFilePath()
{
static const std::vector<const char *> envVarCandidates{"ProgramFiles", "ProgramFiles(x86)"};
@@ -288,7 +282,28 @@ static std::vector<MSVCInstallInfo> installedMSVCsFromRegistry()
return result;
}
-static std::vector<MSVC> installedMSVCs()
+QString MSVCInstallInfo::findVcvarsallBat() const
+{
+ static const auto vcvarsall2017 = QStringLiteral("VC/Auxiliary/Build/vcvarsall.bat");
+ // 2015, 2013 and 2012
+ static const auto vcvarsallOld = QStringLiteral("VC/vcvarsall.bat");
+ QDir dir(installDir);
+ if (dir.exists(vcvarsall2017))
+ return dir.absoluteFilePath(vcvarsall2017);
+ if (dir.exists(vcvarsallOld))
+ return dir.absoluteFilePath(vcvarsallOld);
+ return {};
+}
+
+std::vector<MSVCInstallInfo> installedMSVCs()
+{
+ const auto installInfos = installedMSVCsFromVsWhere();
+ if (installInfos.empty())
+ return installedMSVCsFromRegistry();
+ return installInfos;
+}
+
+static std::vector<MSVC> installedCompilers()
{
std::vector<MSVC> msvcs;
std::vector<MSVCInstallInfo> installInfos = installedMSVCsFromVsWhere();
@@ -385,7 +400,7 @@ void msvcProbe(Settings *settings, QList<Profile> &profiles)
// 2) Installed MSVCs
std::vector<MSVC> msvcs;
- const auto instMsvcs = installedMSVCs();
+ const auto instMsvcs = installedCompilers();
for (const MSVC &msvc : instMsvcs) {
if (msvc.internalVsVersion.majorVersion() < 15) {
// Check existence of various install scripts
@@ -452,7 +467,7 @@ void msvcProbe(Settings *settings, QList<Profile> &profiles)
void createMsvcProfile(const QString &profileName, const QString &compilerFilePath,
Settings *settings)
{
- MSVC msvc(compilerFilePath);
+ MSVC msvc(compilerFilePath, MSVC::architectureFromClPath(compilerFilePath));
msvc.init();
QList<Profile> dummy;
addMSVCPlatform(settings, dummy, profileName, &msvc);
diff --git a/src/app/qbs-setup-toolchains/msvcprobe.h b/src/app/qbs-setup-toolchains/msvcprobe.h
index 0fa209548..4fa2cde48 100644
--- a/src/app/qbs-setup-toolchains/msvcprobe.h
+++ b/src/app/qbs-setup-toolchains/msvcprobe.h
@@ -42,11 +42,23 @@
#include <QtCore/qlist.h>
+#include <vector>
+
namespace qbs {
class Profile;
class Settings;
}
+struct MSVCInstallInfo
+{
+ QString version;
+ QString installDir;
+
+ QString findVcvarsallBat() const;
+};
+
+std::vector<MSVCInstallInfo> installedMSVCs();
+
void createMsvcProfile(const QString &profileName, const QString &compilerFilePath,
qbs::Settings *settings);
diff --git a/src/app/qbs-setup-toolchains/probe.cpp b/src/app/qbs-setup-toolchains/probe.cpp
index c4ccbc517..6deac36ee 100644
--- a/src/app/qbs-setup-toolchains/probe.cpp
+++ b/src/app/qbs-setup-toolchains/probe.cpp
@@ -38,6 +38,7 @@
****************************************************************************/
#include "probe.h"
+#include "clangclprobe.h"
#include "msvcprobe.h"
#include "xcodeprobe.h"
@@ -66,7 +67,7 @@ using Internal::Tr;
static QTextStream qStdout(stdout);
static QTextStream qStderr(stderr);
-static QString findExecutable(const QString &fileName)
+QString findExecutable(const QString &fileName)
{
QString fullFileName = fileName;
if (HostOsInfo::isWindowsHost()
@@ -135,6 +136,8 @@ static QStringList toolchainTypeFromCompilerName(const QString &compilerName)
{
if (compilerName == QLatin1String("cl.exe"))
return canonicalToolchain(QStringLiteral("msvc"));
+ if (compilerName == QLatin1String("clang-cl.exe"))
+ return canonicalToolchain(QLatin1String("clang-cl"));
const auto types = { QStringLiteral("clang"), QStringLiteral("llvm"),
QStringLiteral("mingw"), QStringLiteral("gcc") };
for (const auto &type : types) {
@@ -409,6 +412,7 @@ void probe(Settings *settings)
QList<Profile> profiles;
if (HostOsInfo::isWindowsHost()) {
msvcProbe(settings, profiles);
+ clangClProbe(settings, profiles);
} else {
gccProbe(settings, profiles, QStringLiteral("gcc"));
gccProbe(settings, profiles, QStringLiteral("clang"));
@@ -451,6 +455,8 @@ void createProfile(const QString &profileName, const QString &toolchainType,
if (toolchainTypes.contains(QLatin1String("msvc")))
createMsvcProfile(profileName, compiler.absoluteFilePath(), settings);
+ else if (toolchainTypes.contains(QLatin1String("clang-cl")))
+ createClangClProfile(profileName, compiler.absoluteFilePath(), settings);
else if (toolchainTypes.contains(QLatin1String("gcc")))
createGccProfile(compiler.absoluteFilePath(), settings, toolchainTypes, profileName);
else if (toolchainTypes.contains(QLatin1String("iar")))
diff --git a/src/app/qbs-setup-toolchains/probe.h b/src/app/qbs-setup-toolchains/probe.h
index 5c8774ddb..510747ef7 100644
--- a/src/app/qbs-setup-toolchains/probe.h
+++ b/src/app/qbs-setup-toolchains/probe.h
@@ -48,6 +48,8 @@ QT_END_NAMESPACE
namespace qbs { class Settings; }
+QString findExecutable(const QString &fileName);
+
void createProfile(const QString &profileName, const QString &toolchainType,
const QString &compilerFilePath, qbs::Settings *settings);
diff --git a/src/app/qbs-setup-toolchains/qbs-setup-toolchains.pro b/src/app/qbs-setup-toolchains/qbs-setup-toolchains.pro
index f395c5458..79b9316ad 100644
--- a/src/app/qbs-setup-toolchains/qbs-setup-toolchains.pro
+++ b/src/app/qbs-setup-toolchains/qbs-setup-toolchains.pro
@@ -4,12 +4,14 @@ TARGET = qbs-setup-toolchains
HEADERS += \
commandlineparser.h \
+ clangclprobe.h \
msvcprobe.h \
probe.h \
xcodeprobe.h
SOURCES += \
commandlineparser.cpp \
+ clangclprobe.cpp \
main.cpp \
msvcprobe.cpp \
probe.cpp \
diff --git a/src/app/qbs-setup-toolchains/qbs-setup-toolchains.qbs b/src/app/qbs-setup-toolchains/qbs-setup-toolchains.qbs
index 1b7cb6526..f4a521b22 100644
--- a/src/app/qbs-setup-toolchains/qbs-setup-toolchains.qbs
+++ b/src/app/qbs-setup-toolchains/qbs-setup-toolchains.qbs
@@ -4,6 +4,8 @@ QbsApp {
name: "qbs-setup-toolchains"
cpp.dynamicLibraries: qbs.targetOS.contains("windows") ? base.concat("shell32") : base
files: [
+ "clangclprobe.cpp",
+ "clangclprobe.h",
"commandlineparser.cpp",
"commandlineparser.h",
"main.cpp",
diff --git a/src/lib/corelib/jsextensions/utilitiesextension.cpp b/src/lib/corelib/jsextensions/utilitiesextension.cpp
index 5abaccad9..62778665c 100644
--- a/src/lib/corelib/jsextensions/utilitiesextension.cpp
+++ b/src/lib/corelib/jsextensions/utilitiesextension.cpp
@@ -109,6 +109,7 @@ public:
static QScriptValue js_certificateInfo(QScriptContext *context, QScriptEngine *engine);
static QScriptValue js_signingIdentities(QScriptContext *context, QScriptEngine *engine);
static QScriptValue js_msvcCompilerInfo(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue js_clangClCompilerInfo(QScriptContext *context, QScriptEngine *engine);
static QScriptValue js_versionCompare(QScriptContext *context, QScriptEngine *engine);
@@ -455,6 +456,37 @@ QScriptValue UtilitiesExtension::js_signingIdentities(QScriptContext *context,
#endif
}
+#ifdef Q_OS_WIN
+static std::pair<QVariantMap /*result*/, QString /*error*/> msvcCompilerInfoHelper(
+ const QString &compilerFilePath,
+ MSVC::CompilerLanguage language,
+ const QString &vcvarsallPath,
+ const QString &arch)
+{
+ MSVC msvc(compilerFilePath, arch);
+ VsEnvironmentDetector envdetector(vcvarsallPath);
+ if (!envdetector.start(&msvc))
+ return { {}, QStringLiteral("Detecting the MSVC build environment failed: ")
+ + envdetector.errorString() };
+
+ try {
+ QVariantMap envMap;
+ for (const QString &key : msvc.environment.keys())
+ envMap.insert(key, msvc.environment.value(key));
+
+ return {
+ QVariantMap {
+ {QStringLiteral("buildEnvironment"), envMap},
+ {QStringLiteral("macros"), msvc.compilerDefines(compilerFilePath, language)},
+ },
+ {}
+ };
+ } catch (const qbs::ErrorInfo &info) {
+ return { {}, info.toString() };
+ }
+}
+#endif
+
QScriptValue UtilitiesExtension::js_msvcCompilerInfo(QScriptContext *context, QScriptEngine *engine)
{
#ifndef Q_OS_WIN
@@ -462,14 +494,12 @@ QScriptValue UtilitiesExtension::js_msvcCompilerInfo(QScriptContext *context, QS
return context->throwError(QScriptContext::UnknownError,
QStringLiteral("msvcCompilerInfo is not available on this platform"));
#else
- if (Q_UNLIKELY(context->argumentCount() < 1))
+ if (Q_UNLIKELY(context->argumentCount() < 2))
return context->throwError(QScriptContext::SyntaxError,
- QStringLiteral("msvcCompilerInfo expects at least 1 argument"));
+ QStringLiteral("msvcCompilerInfo expects 2 arguments"));
const QString compilerFilePath = context->argument(0).toString();
- const QString compilerLanguage = context->argumentCount() > 1
- ? context->argument(1).toString()
- : QString();
+ const QString compilerLanguage = context->argument(1).toString();
MSVC::CompilerLanguage language;
if (compilerLanguage == QStringLiteral("c"))
language = MSVC::CLanguage;
@@ -479,26 +509,45 @@ QScriptValue UtilitiesExtension::js_msvcCompilerInfo(QScriptContext *context, QS
return context->throwError(QScriptContext::TypeError,
QStringLiteral("msvcCompilerInfo expects \"c\" or \"cpp\" as its second argument"));
- MSVC msvc(compilerFilePath);
- VsEnvironmentDetector envdetector;
- if (!envdetector.start(&msvc))
- return context->throwError(QScriptContext::UnknownError,
- QStringLiteral("Detecting the MSVC build environment failed: ")
- + envdetector.errorString());
+ const auto result = msvcCompilerInfoHelper(
+ compilerFilePath, language, {}, MSVC::architectureFromClPath(compilerFilePath));
+ if (result.first.isEmpty())
+ return context->throwError(QScriptContext::UnknownError, result.second);
+ return engine->toScriptValue(result.first);
+#endif
+}
- try {
- QVariantMap envMap;
- for (const QString &key : msvc.environment.keys())
- envMap.insert(key, msvc.environment.value(key));
+QScriptValue UtilitiesExtension::js_clangClCompilerInfo(QScriptContext *context, QScriptEngine *engine)
+{
+#ifndef Q_OS_WIN
+ Q_UNUSED(engine);
+ return context->throwError(QScriptContext::UnknownError,
+ QStringLiteral("clangClCompilerInfo is not available on this platform"));
+#else
+ if (Q_UNLIKELY(context->argumentCount() < 4))
+ return context->throwError(QScriptContext::SyntaxError,
+ QStringLiteral("clangClCompilerInfo expects 4 arguments"));
- return engine->toScriptValue(QVariantMap {
- {QStringLiteral("buildEnvironment"), envMap},
- {QStringLiteral("macros"), msvc.compilerDefines(compilerFilePath, language)},
- });
- } catch (const qbs::ErrorInfo &info) {
- return context->throwError(QScriptContext::UnknownError,
- info.toString());
- }
+ const QString compilerFilePath = context->argument(0).toString();
+ QString arch = context->argument(1).toString();
+ QString vcvarsallPath = context->argument(2).toString();
+ const QString compilerLanguage = context->argumentCount() > 3
+ ? context->argument(3).toString()
+ : QString();
+ MSVC::CompilerLanguage language;
+ if (compilerLanguage == QStringLiteral("c"))
+ language = MSVC::CLanguage;
+ else if (compilerLanguage == StringConstants::cppLang())
+ language = MSVC::CPlusPlusLanguage;
+ else
+ return context->throwError(QScriptContext::TypeError,
+ QStringLiteral("clangClCompilerInfo expects \"c\" or \"cpp\" as its fourth argument"));
+
+ const auto result = msvcCompilerInfoHelper(
+ compilerFilePath, language, vcvarsallPath, arch);
+ if (result.first.isEmpty())
+ return context->throwError(QScriptContext::UnknownError, result.second);
+ return engine->toScriptValue(result.first);
#endif
}
@@ -800,6 +849,8 @@ void initializeJsExtensionUtilities(QScriptValue extensionObject)
engine->newFunction(UtilitiesExtension::js_signingIdentities, 0));
environmentObj.setProperty(QStringLiteral("msvcCompilerInfo"),
engine->newFunction(UtilitiesExtension::js_msvcCompilerInfo, 1));
+ environmentObj.setProperty(QStringLiteral("clangClCompilerInfo"),
+ engine->newFunction(UtilitiesExtension::js_clangClCompilerInfo, 1));
environmentObj.setProperty(QStringLiteral("versionCompare"),
engine->newFunction(UtilitiesExtension::js_versionCompare, 2));
environmentObj.setProperty(QStringLiteral("qmlTypeInfo"),
diff --git a/src/lib/corelib/tools/hostosinfo.h b/src/lib/corelib/tools/hostosinfo.h
index cae451638..d7f718c19 100644
--- a/src/lib/corelib/tools/hostosinfo.h
+++ b/src/lib/corelib/tools/hostosinfo.h
@@ -74,6 +74,7 @@ public:
enum HostOs { HostOsWindows, HostOsLinux, HostOsMacos, HostOsOtherUnix, HostOsOther };
static inline std::string hostOSIdentifier();
+ static inline std::string hostOSArchitecture();
static inline std::vector<std::string> hostOSIdentifiers();
static inline std::vector<std::string> canonicalOSIdentifiers(const std::string &os);
static inline HostOs hostOs();
@@ -177,6 +178,14 @@ std::string HostOsInfo::hostOSIdentifier()
#endif
}
+std::string HostOsInfo::hostOSArchitecture()
+{
+ const auto cpuArch = QSysInfo::currentCpuArchitecture();
+ if (cpuArch == QLatin1String("i386"))
+ return "x86";
+ return cpuArch.toStdString();
+}
+
std::vector<std::string> HostOsInfo::hostOSIdentifiers()
{
return canonicalOSIdentifiers(hostOSIdentifier());
diff --git a/src/lib/corelib/tools/msvcinfo.cpp b/src/lib/corelib/tools/msvcinfo.cpp
index c1312c8c9..cffec85b2 100644
--- a/src/lib/corelib/tools/msvcinfo.cpp
+++ b/src/lib/corelib/tools/msvcinfo.cpp
@@ -198,11 +198,88 @@ static QVariantMap getMsvcDefines(const QString &compilerFilePath,
#endif
}
+/*!
+ \internal
+ clang-cl does not support gcc and msvc ways to dump a macros, so we have to use original
+ clang.exe directly
+*/
+static QVariantMap getClangClDefines(
+ const QString &compilerFilePath,
+ const QProcessEnvironment &compilerEnv,
+ MSVC::CompilerLanguage language)
+{
+#ifdef Q_OS_WIN
+ QFileInfo clInfo(compilerFilePath);
+ QFileInfo clangInfo(clInfo.absolutePath() + QLatin1String("/clang.exe"));
+ if (!clangInfo.exists())
+ throw ErrorInfo(QStringLiteral("%1 does not exist").arg(clangInfo.absoluteFilePath()));
+
+ QString languageSwitch;
+ switch (language) {
+ case MSVC::CLanguage:
+ languageSwitch = QStringLiteral("c");
+ break;
+ case MSVC::CPlusPlusLanguage:
+ languageSwitch = QStringLiteral("c++");
+ break;
+ }
+ QStringList args = {
+ QStringLiteral("-dM"),
+ QStringLiteral("-E"),
+ QStringLiteral("-x"),
+ languageSwitch,
+ QStringLiteral("NUL"),
+ };
+ const auto lines = QString::fromLocal8Bit(
+ runProcess(
+ clangInfo.absoluteFilePath(),
+ args,
+ compilerEnv,
+ true)).split(QLatin1Char('\n'));
+ QVariantMap result;
+ for (const auto &line: lines) {
+ static const auto defineString = QLatin1String("#define ");
+ if (!line.startsWith(defineString)) {
+ throw ErrorInfo(QStringLiteral("Unexpected compiler frontend output: ")
+ + lines.join(QLatin1Char('\n')));
+ }
+ QStringView view(line.data() + defineString.size());
+ const auto it = std::find(view.begin(), view.end(), QLatin1Char(' '));
+ if (it == view.end()) {
+ throw ErrorInfo(QStringLiteral("Unexpected compiler frontend output: ")
+ + lines.join(QLatin1Char('\n')));
+ }
+ QStringView key(view.begin(), it);
+ QStringView value(it + 1, view.end());
+ result.insert(key.toString(), value.isEmpty() ? QVariant() : QVariant(value.toString()));
+ }
+ return result;
+#else
+ Q_UNUSED(compilerFilePath);
+ Q_UNUSED(compilerEnv);
+ Q_UNUSED(language);
+ return {};
+#endif
+}
+
void MSVC::init()
{
determineCompilerVersion();
}
+/*!
+ \internal
+ Returns the architecture detected from the compiler path.
+*/
+QString MSVC::architectureFromClPath(const QString &clPath)
+{
+ const auto parentDir = QFileInfo(clPath).absolutePath();
+ const auto parentDirName = QFileInfo(parentDir).fileName().toLower();
+ if (parentDirName == QLatin1String("bin"))
+ return QStringLiteral("x86");
+ return parentDirName;
+}
+
QString MSVC::binPathForArchitecture(const QString &arch) const
{
QString archSubDir;
@@ -222,6 +299,9 @@ QString MSVC::clPathForArchitecture(const QString &arch) const
QVariantMap MSVC::compilerDefines(const QString &compilerFilePath,
MSVC::CompilerLanguage language) const
{
+ const auto compilerName = QFileInfo(compilerFilePath).fileName().toLower();
+ if (compilerName == QLatin1String("clang-cl.exe"))
+ return getClangClDefines(compilerFilePath, environment, language);
return getMsvcDefines(compilerFilePath, environment, language);
}
diff --git a/src/lib/corelib/tools/msvcinfo.h b/src/lib/corelib/tools/msvcinfo.h
index 61a19dc4f..5f542fc97 100644
--- a/src/lib/corelib/tools/msvcinfo.h
+++ b/src/lib/corelib/tools/msvcinfo.h
@@ -77,20 +77,19 @@ public:
MSVC() { }
- MSVC(const QString &clPath)
+ MSVC(const QString &clPath, QString arch):
+ architecture(std::move(arch))
{
QDir parentDir = QFileInfo(clPath).dir();
binPath = parentDir.absolutePath();
QString parentDirName = parentDir.dirName().toLower();
- if (parentDirName == QLatin1String("bin"))
- parentDirName = QStringLiteral("x86");
- else
+ if (parentDirName != QLatin1String("bin"))
parentDir.cdUp();
- architecture = parentDirName;
vcInstallPath = parentDir.path();
}
QBS_EXPORT void init();
+ QBS_EXPORT static QString architectureFromClPath(const QString &clPath);
QBS_EXPORT QString binPathForArchitecture(const QString &arch) const;
QBS_EXPORT QString clPathForArchitecture(const QString &arch) const;
QBS_EXPORT QVariantMap compilerDefines(const QString &compilerFilePath,
diff --git a/src/lib/corelib/tools/vsenvironmentdetector.cpp b/src/lib/corelib/tools/vsenvironmentdetector.cpp
index 869423950..90f6b8921 100644
--- a/src/lib/corelib/tools/vsenvironmentdetector.cpp
+++ b/src/lib/corelib/tools/vsenvironmentdetector.cpp
@@ -69,8 +69,9 @@ static QString windowsSystem32Path()
return {};
}
-VsEnvironmentDetector::VsEnvironmentDetector()
+VsEnvironmentDetector::VsEnvironmentDetector(QString vcvarsallPath)
: m_windowsSystemDirPath(windowsSystem32Path())
+ , m_vcvarsallPath(std::move(vcvarsallPath))
{
}
@@ -137,7 +138,15 @@ QString VsEnvironmentDetector::findVcVarsAllBat(const MSVC &msvc,
bool VsEnvironmentDetector::startDetection(const std::vector<MSVC *> &compatibleMSVCs)
{
std::vector<QString> searchedPaths;
- const QString vcvarsallbat = findVcVarsAllBat(**compatibleMSVCs.begin(), searchedPaths);
+
+ if (!m_vcvarsallPath.isEmpty() && !QFileInfo::exists(m_vcvarsallPath)) {
+ m_errorString = Tr::tr("%1 does not exist.").arg(m_vcvarsallPath);
+ return false;
+ }
+
+ const auto vcvarsallbat = !m_vcvarsallPath.isEmpty()
+ ? m_vcvarsallPath
+ : findVcVarsAllBat(**compatibleMSVCs.begin(), searchedPaths);
if (vcvarsallbat.isEmpty()) {
if (!searchedPaths.empty()) {
m_errorString = Tr::tr(
diff --git a/src/lib/corelib/tools/vsenvironmentdetector.h b/src/lib/corelib/tools/vsenvironmentdetector.h
index 1970273ee..7fa152cb6 100644
--- a/src/lib/corelib/tools/vsenvironmentdetector.h
+++ b/src/lib/corelib/tools/vsenvironmentdetector.h
@@ -57,7 +57,7 @@ class MSVC;
class QBS_EXPORT VsEnvironmentDetector
{
public:
- VsEnvironmentDetector();
+ explicit VsEnvironmentDetector(QString vcvarsallPath = QString());
bool start(MSVC *msvc);
bool start(std::vector<MSVC *> msvcs);
@@ -70,6 +70,7 @@ private:
void parseBatOutput(const QByteArray &output, std::vector<MSVC *> msvcs);
const QString m_windowsSystemDirPath;
+ const QString m_vcvarsallPath;
QString m_errorString;
};
diff --git a/tests/auto/api/testdata/app-without-sources/app-without-sources.qbs b/tests/auto/api/testdata/app-without-sources/app-without-sources.qbs
index a366e0ce0..4cc25ad66 100644
--- a/tests/auto/api/testdata/app-without-sources/app-without-sources.qbs
+++ b/tests/auto/api/testdata/app-without-sources/app-without-sources.qbs
@@ -28,6 +28,7 @@ Project {
Properties {
condition: qbs.toolchain.contains("msvc")
cpp.entryPoint: "main"
+ cpp.dynamicLibraries: ["ucrt", "kernel32"]
}
cpp.entryPoint: undefined
diff --git a/tests/auto/api/testdata/precompiled-header-dynamic/autogen.h.in b/tests/auto/api/testdata/precompiled-header-dynamic/autogen.h.in
index c5c182c8f..becfbba89 100644
--- a/tests/auto/api/testdata/precompiled-header-dynamic/autogen.h.in
+++ b/tests/auto/api/testdata/precompiled-header-dynamic/autogen.h.in
@@ -1 +1,6 @@
+#ifndef AUTOGEN_IN_H
+#define AUTOGEN_IN_H
+
inline void f() { }
+
+#endif // AUTOGEN_IN_H
diff --git a/tests/auto/blackbox/testdata/cxx-language-version/cxx-language-version.qbs b/tests/auto/blackbox/testdata/cxx-language-version/cxx-language-version.qbs
index 6beaabfa3..322ded85c 100644
--- a/tests/auto/blackbox/testdata/cxx-language-version/cxx-language-version.qbs
+++ b/tests/auto/blackbox/testdata/cxx-language-version/cxx-language-version.qbs
@@ -13,7 +13,10 @@ CppApplication {
var isEvenNewerMsvc;
var isOlderMsvc;
var isGcc;
- if (toolchain.contains("msvc")) {
+ if (toolchain.contains("clang-cl")) {
+ isEvenNewerMsvc = true;
+ isNewerMsvc = true;
+ } else if (toolchain.contains("msvc")) {
if (compilerVersion >= "19.12.25831")
isEvenNewerMsvc = true;
if (compilerVersion >= "18.00.30723")
diff --git a/tests/auto/blackbox/testdata/enableRtti/main.cpp b/tests/auto/blackbox/testdata/enableRtti/main.cpp
index 4dcd5d2e8..4011cf823 100644
--- a/tests/auto/blackbox/testdata/enableRtti/main.cpp
+++ b/tests/auto/blackbox/testdata/enableRtti/main.cpp
@@ -32,6 +32,10 @@
#error RTTI is disabled!
#endif
+#if defined(_MSC_VER) && !defined (_CPPRTTI)
+#error RTTI is disabled!
+#endif
+
class I {
public:
virtual ~I() { }
diff --git a/tests/auto/blackbox/testdata/minimumSystemVersion/main.cpp b/tests/auto/blackbox/testdata/minimumSystemVersion/main.cpp
index 4cc99756b..47c9ed007 100644
--- a/tests/auto/blackbox/testdata/minimumSystemVersion/main.cpp
+++ b/tests/auto/blackbox/testdata/minimumSystemVersion/main.cpp
@@ -42,6 +42,10 @@ int main(int argc, char *argv[])
return 1;
#ifdef _WIN32
+#if defined(__clang__)
+ std::cout << "Unsupported compiler" << std::endl;
+ return 0;
+#endif
#if defined(WINVER) && defined(QBS_WINVER)
std::cout << "WINVER=" << WINVER << std::endl;
std::string command = TOOLCHAIN_INSTALL_PATH;
diff --git a/tests/auto/blackbox/testdata/no-exported-symbols/no-exported-symbols.qbs b/tests/auto/blackbox/testdata/no-exported-symbols/no-exported-symbols.qbs
index 4bda00caf..346a94e21 100644
--- a/tests/auto/blackbox/testdata/no-exported-symbols/no-exported-symbols.qbs
+++ b/tests/auto/blackbox/testdata/no-exported-symbols/no-exported-symbols.qbs
@@ -12,7 +12,7 @@ Project {
id: toolchainProbe
property stringList toolchain: qbs.toolchain
configure: {
- if (toolchain.contains("msvc"))
+ if (toolchain.contains("msvc") && !toolchain.contains("clang-cl"))
console.info("compiler is MSVC")
else
console.info("compiler is not MSVC")
diff --git a/tests/auto/blackbox/tst_blackbox.cpp b/tests/auto/blackbox/tst_blackbox.cpp
index ca11e4e3e..219a473e0 100644
--- a/tests/auto/blackbox/tst_blackbox.cpp
+++ b/tests/auto/blackbox/tst_blackbox.cpp
@@ -6414,6 +6414,8 @@ void TestBlackbox::minimumSystemVersion()
QbsRunParameters params({ "-f", file + ".qbs" });
params.command = "run";
QCOMPARE(runQbs(params), 0);
+ if (m_qbsStdout.contains("Unsupported compiler"))
+ QSKIP("Unsupported compiler");
if (!m_qbsStdout.contains(output.toUtf8())) {
qDebug() << "expected output:" << qPrintable(output);
qDebug() << "actual output:" << m_qbsStdout.constData();