diff options
author | Christian Kandeler <christian.kandeler@qt.io> | 2019-07-22 15:51:50 +0200 |
---|---|---|
committer | Christian Kandeler <christian.kandeler@qt.io> | 2019-08-14 11:44:51 +0000 |
commit | 18a3b64ab07ade6bfc9bb068956beed2032d9b58 (patch) | |
tree | 7bcb18c36f05508457074d783197cdd3f37f9fd6 /share | |
parent | 5320c8578b600081d9c5174f4024b726c5bdefa0 (diff) |
C++: Add support for clang on Windows
This is about clang in "mingw mode", not clang-cl.
When targeting Windows, clang is a lot like mingw, so factor out the
common parts into a new base module.
Testing uncovered a number of invalid assumptions in our autotests,
which are also fixed in this patch. In addition, minor adjustments had
to be made to the Qt.core module and to the qbscore lib.
Change-Id: I73085dc62a65e2a9d0397cf234c8641989246f22
Reviewed-by: Ivan Komissarov <ABBAPOH@gmail.com>
Reviewed-by: Jörg Bornemann <joerg.bornemann@qt.io>
Diffstat (limited to 'share')
-rw-r--r-- | share/qbs/module-providers/Qt/templates/core.qbs | 4 | ||||
-rw-r--r-- | share/qbs/modules/cpp/GenericGCC.qbs | 16 | ||||
-rw-r--r-- | share/qbs/modules/cpp/MingwBaseModule.qbs | 115 | ||||
-rw-r--r-- | share/qbs/modules/cpp/gcc.js | 26 | ||||
-rw-r--r-- | share/qbs/modules/cpp/msvc.js | 43 | ||||
-rw-r--r-- | share/qbs/modules/cpp/windows-clang-mingw.qbs | 98 | ||||
-rw-r--r-- | share/qbs/modules/cpp/windows-mingw.qbs | 88 | ||||
-rw-r--r-- | share/qbs/modules/cpp/windows-msvc-base.qbs | 48 |
8 files changed, 296 insertions, 142 deletions
diff --git a/share/qbs/module-providers/Qt/templates/core.qbs b/share/qbs/module-providers/Qt/templates/core.qbs index 98bc0c4d3..8e990db22 100644 --- a/share/qbs/module-providers/Qt/templates/core.qbs +++ b/share/qbs/module-providers/Qt/templates/core.qbs @@ -105,6 +105,10 @@ Module { condition: moduleConfig.contains("use_gold_linker") cpp.linkerVariant: "gold" } + Properties { + condition: !moduleConfig.contains("use_gold_linker") && qbs.toolchain.contains("gcc") + cpp.linkerVariant: original + } cpp.cxxLanguageVersion: Utilities.versionCompare(version, "5.7.0") >= 0 ? "c++11" : original cpp.enableCompilerDefinesByLanguage: ["cpp"].concat( diff --git a/share/qbs/modules/cpp/GenericGCC.qbs b/share/qbs/modules/cpp/GenericGCC.qbs index f9537884e..3b775c9fa 100644 --- a/share/qbs/modules/cpp/GenericGCC.qbs +++ b/share/qbs/modules/cpp/GenericGCC.qbs @@ -135,14 +135,14 @@ CppModule { : undefined property string binutilsPath: binutilsProbe.found ? binutilsProbe.path : toolchainInstallPath - assemblerName: 'as' + assemblerName: 'as' + compilerExtension compilerName: cxxCompilerName - linkerName: 'ld' - property string archiverName: 'ar' - property string nmName: 'nm' - property string objcopyName: "objcopy" - property string stripName: "strip" - property string dsymutilName: "dsymutil" + linkerName: 'ld' + compilerExtension + property string archiverName: 'ar' + compilerExtension + property string nmName: 'nm' + compilerExtension + property string objcopyName: "objcopy" + compilerExtension + property string stripName: "strip" + compilerExtension + property string dsymutilName: "dsymutil" + compilerExtension property string lipoName property string sysroot: qbs.sysroot property string syslibroot: sysroot @@ -429,7 +429,7 @@ CppModule { + PathTools.bundleExecutableFilePath(product) } }]; - if (product.qbs.toolchain.contains("mingw")) { + if (product.cpp.imageFormat === "pe") { artifacts.push({ fileTags: ["dynamiclibrary_import"], filePath: FileInfo.joinPaths(product.destinationDirectory, diff --git a/share/qbs/modules/cpp/MingwBaseModule.qbs b/share/qbs/modules/cpp/MingwBaseModule.qbs new file mode 100644 index 000000000..60ad28b08 --- /dev/null +++ b/share/qbs/modules/cpp/MingwBaseModule.qbs @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing +** +** This file is part of Qbs. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms and +** conditions see http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +import qbs.TextFile +import qbs.Utilities +import qbs.WindowsUtils + +import "setuprunenv.js" as SetupRunEnv + +GenericGCC { + condition: false + + staticLibraryPrefix: "lib" + staticLibrarySuffix: ".a" + dynamicLibrarySuffix: ".dll" + executableSuffix: ".exe" + debugInfoSuffix: ".debug" + imageFormat: "pe" + windowsApiCharacterSet: "unicode" + platformDefines: base.concat(WindowsUtils.characterSetDefines(windowsApiCharacterSet)) + .concat("WIN32") + + Properties { + condition: product.multiplexByQbsProperties.contains("buildVariants") + && qbs.buildVariants && qbs.buildVariants.length > 1 + && qbs.buildVariant !== "release" + && product.type.containsAny(["staticlibrary", "dynamiclibrary"]) + variantSuffix: "d" + } + + FileTagger { + patterns: ["*.manifest"] + fileTags: ["native.pe.manifest"] + } + + FileTagger { + patterns: ["*.rc"] + fileTags: ["rc"] + } + + Rule { + inputs: ["native.pe.manifest"] + multiplex: true + + outputFileTags: ["rc"] + outputArtifacts: { + if (product.type.containsAny(["application", "dynamiclibrary"])) { + return [{ + filePath: input.completeBaseName + ".rc", + fileTags: ["rc"] + }]; + } + return []; + } + + prepare: { + var inputList = inputs["native.pe.manifest"]; + // TODO: Emulate manifest merging like Microsoft's mt.exe tool does + if (inputList.length !== 1) { + throw("The MinGW toolchain does not support manifest merging; " + + "you may only specify a single manifest file to embed into your assembly."); + } + + var cmd = new JavaScriptCommand(); + cmd.silent = true; + cmd.productType = product.type; + cmd.inputFilePath = inputList[0].filePath; + cmd.outputFilePath = output.filePath; + cmd.sourceCode = function() { + var tf; + try { + tf = new TextFile(outputFilePath, TextFile.WriteOnly); + if (productType.contains("application")) + tf.write("1 "); // CREATEPROCESS_MANIFEST_RESOURCE_ID + else if (productType.contains("dynamiclibrary")) + tf.write("2 "); // ISOLATIONAWARE_MANIFEST_RESOURCE_ID + tf.write("24 "); // RT_MANIFEST + tf.writeLine(Utilities.cStringQuote(inputFilePath)); + } finally { + if (tf) + tf.close(); + } + }; + return [cmd]; + } + } +} + diff --git a/share/qbs/modules/cpp/gcc.js b/share/qbs/modules/cpp/gcc.js index 6936beb5e..f1cee8231 100644 --- a/share/qbs/modules/cpp/gcc.js +++ b/share/qbs/modules/cpp/gcc.js @@ -78,7 +78,7 @@ function collectLibraryDependencies(product, isDarwin) { var publicDeps = {}; var objects = []; var objectByFilePath = {}; - var tagForLinkingAgainstSharedLib = product.qbs.toolchain.contains("mingw") + var tagForLinkingAgainstSharedLib = product.cpp.imageFormat === "pe" ? "dynamiclibrary_import" : "dynamiclibrary"; function addObject(obj, addFunc) { @@ -283,7 +283,7 @@ function linkerFlags(project, product, inputs, outputs, primaryOutput, linkerPat args.push("-current_version", internalVersion); escapableLinkerFlags.push("-install_name", UnixUtils.soname(product, primaryOutput.fileName)); - } else { + } else if (product.cpp.imageFormat === "elf") { escapableLinkerFlags.push("-soname=" + UnixUtils.soname(product, primaryOutput.fileName)); } @@ -295,7 +295,7 @@ function linkerFlags(project, product, inputs, outputs, primaryOutput, linkerPat if (primaryOutput.fileTags.containsAny(["dynamiclibrary", "loadablemodule"])) { if (isDarwin) escapableLinkerFlags.push("-headerpad_max_install_names"); - else + else if (product.cpp.imageFormat === "elf") escapableLinkerFlags.push("--as-needed"); } @@ -344,13 +344,15 @@ function linkerFlags(project, product, inputs, outputs, primaryOutput, linkerPat return rpath; } - function isNotSystemRunPath(p) { - return !FileInfo.isAbsolutePath(p) || (!systemRunPaths.contains(p) - && !canonicalSystemRunPaths.contains(File.canonicalFilePath(p))); - }; - for (i in rpaths) { - if (isNotSystemRunPath(rpaths[i])) - escapableLinkerFlags.push("-rpath", fixupRPath(rpaths[i])); + if (!product.qbs.targetOS.contains("windows")) { + function isNotSystemRunPath(p) { + return !FileInfo.isAbsolutePath(p) || (!systemRunPaths.contains(p) + && !canonicalSystemRunPaths.contains(File.canonicalFilePath(p))); + }; + for (i in rpaths) { + if (isNotSystemRunPath(rpaths[i])) + escapableLinkerFlags.push("-rpath", fixupRPath(rpaths[i])); + } } if (product.cpp.entryPoint) @@ -854,7 +856,7 @@ function compilerFlags(project, product, input, output, explicitlyDependsOn) { } var positionIndependentCode = input.cpp.positionIndependentCode; - if (positionIndependentCode && !product.qbs.toolchain.contains("mingw")) + if (positionIndependentCode && !product.qbs.targetOS.contains("windows")) args.push('-fPIC'); var cppFlags = input.cpp.cppFlags; @@ -1035,7 +1037,7 @@ function linkerEnvVars(config, inputs) function setResponseFileThreshold(command, product) { - if (product.qbs.toolchain.contains("mingw") && product.qbs.hostOS.contains("windows")) + if (product.qbs.targetOS.contains("windows") && product.qbs.hostOS.contains("windows")) command.responseFileThreshold = 10000; } diff --git a/share/qbs/modules/cpp/msvc.js b/share/qbs/modules/cpp/msvc.js index 9deffa064..02facf30a 100644 --- a/share/qbs/modules/cpp/msvc.js +++ b/share/qbs/modules/cpp/msvc.js @@ -542,3 +542,46 @@ function prepareLinker(project, product, inputs, outputs, input, output) { return commands; } +function createRcCommand(binary, input, output, logo) { + var platformDefines = input.cpp.platformDefines; + var defines = input.cpp.defines; + var includePaths = input.cpp.includePaths; + var systemIncludePaths = input.cpp.systemIncludePaths; + + var args = []; + if (logo === "can-suppress-logo") + args.push("/nologo"); + for (i in platformDefines) { + args.push("/d"); + args.push(platformDefines[i]); + } + for (i in defines) { + args.push("/d"); + args.push(defines[i]); + } + for (i in includePaths) { + args.push("/I"); + args.push(includePaths[i]); + } + for (i in systemIncludePaths) { + args.push("/I"); + args.push(systemIncludePaths[i]); + } + args = args.concat(["/FO", output.filePath, input.filePath]); + var cmd = new Command(binary, args); + cmd.description = 'compiling ' + input.fileName; + cmd.highlight = 'compiler'; + cmd.jobPool = "compiler"; + + if (logo === "always-shows-logo") { + // Remove the first two lines of stdout. That's the logo. + cmd.stdoutFilterFunction = function(output) { + var idx = 0; + for (var i = 0; i < 3; ++i) + idx = output.indexOf('\n', idx + 1); + return output.substr(idx + 1); + } + } + + return cmd; +} diff --git a/share/qbs/modules/cpp/windows-clang-mingw.qbs b/share/qbs/modules/cpp/windows-clang-mingw.qbs new file mode 100644 index 000000000..8389dbf2e --- /dev/null +++ b/share/qbs/modules/cpp/windows-clang-mingw.qbs @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing +** +** This file is part of Qbs. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms and +** conditions see http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +import qbs.File +import qbs.FileInfo +import qbs.ModUtils +import qbs.Utilities +import "msvc.js" as MSVC + +import "setuprunenv.js" as SetupRunEnv + +MingwBaseModule { + condition: qbs.targetOS.contains("windows") && + qbs.toolchain && qbs.toolchain.contains("clang") + priority: 0 + + // llvm-as and llvm-objopy are not shipped with the official binaries on Windows at the + // moment (8.0). We fall back to using the mingw versions in that case. + assemblerName: "llvm-as" + compilerExtension + assemblerPath: { + if (File.exists(base)) + return base; + if (qbs.sysroot) + return FileInfo.joinPaths(qbs.sysroot, "bin", "as" + compilerExtension); + } + objcopyName: "llvm-objcopy" + compilerExtension + objcopyPath: { + if (File.exists(base)) + return base; + if (qbs.sysroot) + return FileInfo.joinPaths(qbs.sysroot, "bin", "objcopy" + compilerExtension); + } + + archiverName: "llvm-ar" + compilerExtension + + linkerVariant: "lld" + targetVendor: "pc" + targetSystem: "windows" + targetAbi: "gnu" + property string rcFilePath: FileInfo.joinPaths(toolchainInstallPath, + "llvm-rc" + compilerExtension) + + setupBuildEnvironment: { + if (product.qbs.hostOS.contains("windows") && product.qbs.sysroot) { + var v = new ModUtils.EnvironmentVariable("PATH", product.qbs.pathListSeparator, true); + v.prepend(FileInfo.joinPaths(product.qbs.sysroot, "bin")); + v.set(); + } + } + + setupRunEnvironment: { + if (product.qbs.hostOS.contains("windows") && product.qbs.sysroot) { + var v = new ModUtils.EnvironmentVariable("PATH", product.qbs.pathListSeparator, true); + v.prepend(FileInfo.joinPaths(product.qbs.sysroot, "bin")); + v.set(); + SetupRunEnv.setupRunEnvironment(product, config); + } + } + + Rule { + inputs: ["rc"] + auxiliaryInputs: ["hpp"] + + Artifact { + filePath: Utilities.getHash(input.baseDir) + "/" + input.completeBaseName + ".res" + fileTags: ["obj"] + } + + prepare: MSVC.createRcCommand(product.cpp.rcFilePath, input, output); + } +} diff --git a/share/qbs/modules/cpp/windows-mingw.qbs b/share/qbs/modules/cpp/windows-mingw.qbs index 27382742f..fe9fd4bf8 100644 --- a/share/qbs/modules/cpp/windows-mingw.qbs +++ b/share/qbs/modules/cpp/windows-mingw.qbs @@ -28,39 +28,28 @@ ** ****************************************************************************/ +import qbs.File +import qbs.FileInfo import qbs.ModUtils -import qbs.TextFile import qbs.Utilities -import qbs.WindowsUtils import "setuprunenv.js" as SetupRunEnv -GenericGCC { +MingwBaseModule { condition: qbs.targetOS.contains("windows") && qbs.toolchain && qbs.toolchain.contains("mingw") priority: 0 - staticLibraryPrefix: "lib" - staticLibrarySuffix: ".a" - dynamicLibrarySuffix: ".dll" - executableSuffix: ".exe" - debugInfoSuffix: ".debug" - imageFormat: "pe" - windowsApiCharacterSet: "unicode" - platformDefines: base.concat(WindowsUtils.characterSetDefines(windowsApiCharacterSet)) - .concat("WIN32") + probeEnv: buildEnv - Properties { - condition: product.multiplexByQbsProperties.contains("buildVariants") - && qbs.buildVariants && qbs.buildVariants.length > 1 - && qbs.buildVariant !== "release" - && product.type.containsAny(["staticlibrary", "dynamiclibrary"]) - variantSuffix: "d" + property string windresName: "windres" + compilerExtension + property path windresPath: { + var filePath = toolchainPrefix + windresName; + if (!File.exists(filePath)) + filePath = FileInfo.joinPaths(toolchainInstallPath, windresName); + return filePath; } - property string windresName: 'windres' - property path windresPath: { return toolchainPathPrefix + windresName } - setupBuildEnvironment: { var v = new ModUtils.EnvironmentVariable("PATH", product.qbs.pathListSeparator, true); v.prepend(product.cpp.toolchainInstallPath); @@ -74,63 +63,6 @@ GenericGCC { SetupRunEnv.setupRunEnvironment(product, config); } - FileTagger { - patterns: ["*.manifest"] - fileTags: ["native.pe.manifest"] - } - - Rule { - inputs: ["native.pe.manifest"] - multiplex: true - - outputFileTags: ["rc"] - outputArtifacts: { - if (product.type.containsAny(["application", "dynamiclibrary"])) { - return [{ - filePath: input.completeBaseName + ".rc", - fileTags: ["rc"] - }]; - } - return []; - } - - prepare: { - var inputList = inputs["native.pe.manifest"]; - // TODO: Emulate manifest merging like Microsoft's mt.exe tool does - if (inputList.length !== 1) { - throw("The MinGW toolchain does not support manifest merging; " + - "you may only specify a single manifest file to embed into your assembly."); - } - - var cmd = new JavaScriptCommand(); - cmd.silent = true; - cmd.productType = product.type; - cmd.inputFilePath = inputList[0].filePath; - cmd.outputFilePath = output.filePath; - cmd.sourceCode = function() { - var tf; - try { - tf = new TextFile(outputFilePath, TextFile.WriteOnly); - if (productType.contains("application")) - tf.write("1 "); // CREATEPROCESS_MANIFEST_RESOURCE_ID - else if (productType.contains("dynamiclibrary")) - tf.write("2 "); // ISOLATIONAWARE_MANIFEST_RESOURCE_ID - tf.write("24 "); // RT_MANIFEST - tf.writeLine(Utilities.cStringQuote(inputFilePath)); - } finally { - if (tf) - tf.close(); - } - }; - return [cmd]; - } - } - - FileTagger { - patterns: ["*.rc"] - fileTags: ["rc"] - } - Rule { inputs: ["rc"] auxiliaryInputs: ["hpp"] diff --git a/share/qbs/modules/cpp/windows-msvc-base.qbs b/share/qbs/modules/cpp/windows-msvc-base.qbs index d36daa99f..ae105abe2 100644 --- a/share/qbs/modules/cpp/windows-msvc-base.qbs +++ b/share/qbs/modules/cpp/windows-msvc-base.qbs @@ -291,50 +291,10 @@ CppModule { } 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; + // From MSVC 2010 on, the logo can be suppressed. + var logo = product.cpp.compilerVersionMajor >= 16 + ? "can-suppress-logo" : "always-shows-logo"; + return MSVC.createRcCommand("rc", input, output, logo); } } |