aboutsummaryrefslogtreecommitdiffstats
path: root/share
diff options
context:
space:
mode:
authorIvan Komissarov <abbapoh@gmail.com>2019-12-12 20:47:27 +0100
committerIvan Komissarov <ABBAPOH@gmail.com>2020-01-24 09:11:04 +0000
commit9c282ff7bd13b25118da3e6d7a46e75fe78caf4c (patch)
tree84bbea00869bd2902e91ffdd464b4ff27db339ce /share
parent1e7875f00e406b762065f0ea2fe30836829fdd42 (diff)
MSVC: Use compiler driver for linking
To be able to use cpp.driverFlags and cpp.driverLinkerFlags with clang- cl. This patchset makes possible to use clang-cl with "- fsanitize=address" flag without passing the sanitizer libraries manually to the linker There's also a behavior change in which linker is used - clang-cl uses native linker by default. Old behavior can be restored by setting cpp.linkerVariant to "lld" Fixes: QBS-1522 Change-Id: I9528ce40aa5fdfab987672b15fffd830fa2d6376 Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
Diffstat (limited to 'share')
-rw-r--r--share/qbs/modules/cpp/CppModule.qbs15
-rw-r--r--share/qbs/modules/cpp/GenericGCC.qbs15
-rw-r--r--share/qbs/modules/cpp/msvc.js152
-rw-r--r--share/qbs/modules/cpp/windows-clang-cl.qbs11
4 files changed, 133 insertions, 60 deletions
diff --git a/share/qbs/modules/cpp/CppModule.qbs b/share/qbs/modules/cpp/CppModule.qbs
index bdd6d2750..173c3f3e5 100644
--- a/share/qbs/modules/cpp/CppModule.qbs
+++ b/share/qbs/modules/cpp/CppModule.qbs
@@ -193,6 +193,21 @@ Module {
property bool discardUnusedData
property bool removeDuplicateLibraries: true
+ property string linkerMode: "automatic"
+ PropertyOptions {
+ name: "linkerMode"
+ allowedValues: ["automatic", "manual"]
+ description: "Controls whether to automatically use an appropriate compiler frontend "
+ + "in place of the system linker when linking binaries. The default is \"automatic\", "
+ + "which chooses either the C++ compiler, C compiler, or system linker specified by "
+ + "the linkerName/linkerPath properties, depending on the type of object files "
+ + "present on the linker command line. \"manual\" allows you to explicitly specify "
+ + "the linker using the linkerName/linkerPath properties, and allows linker flags "
+ + "passed to the linkerFlags and platformLinkerFlags properties to be escaped "
+ + "manually (using -Wl or -Xlinker) instead of automatically based on the selected "
+ + "linker."
+ }
+
property stringList assemblerFlags
PropertyOptions {
name: "assemblerFlags"
diff --git a/share/qbs/modules/cpp/GenericGCC.qbs b/share/qbs/modules/cpp/GenericGCC.qbs
index 63d5db7b8..80de576a9 100644
--- a/share/qbs/modules/cpp/GenericGCC.qbs
+++ b/share/qbs/modules/cpp/GenericGCC.qbs
@@ -148,21 +148,6 @@ CppModule {
property string syslibroot: sysroot
property stringList sysrootFlags: sysroot ? ["--sysroot=" + sysroot] : []
- property string linkerMode: "automatic"
- PropertyOptions {
- name: "linkerMode"
- allowedValues: ["automatic", "manual"]
- description: "Controls whether to automatically use an appropriate compiler frontend "
- + "in place of the system linker when linking binaries. The default is \"automatic\", "
- + "which chooses either the C++ compiler, C compiler, or system linker specified by "
- + "the linkerName/linkerPath properties, depending on the type of object files "
- + "present on the linker command line. \"manual\" allows you to explicitly specify "
- + "the linker using the linkerName/linkerPath properties, and allows linker flags "
- + "passed to the linkerFlags and platformLinkerFlags properties to be escaped "
- + "manually (using -Wl or -Xlinker) instead of automatically based on the selected "
- + "linker."
- }
-
property string exportedSymbolsCheckMode: "ignore-undefined"
PropertyOptions {
name: "exportedSymbolsCheckMode"
diff --git a/share/qbs/modules/cpp/msvc.js b/share/qbs/modules/cpp/msvc.js
index dead67b43..479f7f416 100644
--- a/share/qbs/modules/cpp/msvc.js
+++ b/share/qbs/modules/cpp/msvc.js
@@ -35,6 +35,22 @@ var ModUtils = require("qbs.ModUtils");
var Utilities = require("qbs.Utilities");
var WindowsUtils = require("qbs.WindowsUtils");
+function effectiveLinkerPath(product, inputs) {
+ if (product.cpp.linkerMode === "automatic") {
+ var compiler = product.cpp.compilerPath;
+ if (compiler) {
+ if (inputs.obj || inputs.staticlibrary) {
+ console.log("Found C/C++ objects, using compiler as a linker for " + product.name);
+ return compiler;
+ }
+ }
+
+ console.log("Found no C-language objects, choosing system linker for " + product.name);
+ }
+
+ return product.cpp.linkerPath;
+}
+
function handleCpuFeatures(input, flags) {
if (!input.qbs.architecture)
return;
@@ -90,6 +106,15 @@ function addLanguageVersionFlag(input, args) {
args.push(flag);
}
+function handleClangClArchitectureFlags(product, architecture, flags) {
+ if (product.qbs.toolchain.contains("clang-cl")) {
+ if (architecture === "x86")
+ flags.push("-m32");
+ else if (architecture === "x86_64")
+ flags.push("-m64");
+ }
+}
+
function prepareCompiler(project, product, inputs, outputs, input, output, explicitlyDependsOn) {
var i;
var debugInformation = input.cpp.debugInformation;
@@ -135,12 +160,7 @@ function prepareCompiler(project, product, inputs, outputs, input, output, expli
break;
}
- if (input.qbs.toolchain.contains("clang-cl")) {
- if (input.cpp.architecture === "x86")
- args.push("-m32");
- else if (input.cpp.architecture === "x86_64")
- args.push("-m64");
- }
+ handleClangClArchitectureFlags(product, input.cpp.architecture, args);
if (debugInformation) {
if (product.cpp.separateDebugInformation)
@@ -157,6 +177,10 @@ function prepareCompiler(project, product, inputs, outputs, input, output, expli
args.push(rtl);
}
+ var driverFlags = product.cpp.driverFlags;
+ if (driverFlags)
+ args = args.concat(driverFlags);
+
// warnings:
var warningLevel = input.cpp.warningLevel;
if (warningLevel === 'none')
@@ -368,44 +392,71 @@ function prepareLinker(project, product, inputs, outputs, input, output) {
return a.filePath;
});
var generateManifestFiles = !linkDLL && product.cpp.generateManifestFile;
- var canEmbedManifest = (product.cpp.compilerVersionMajor >= 17); // VS 2012
+ var useClangCl = product.qbs.toolchain.contains("clang-cl");
+ var canEmbedManifest = useClangCl || product.cpp.compilerVersionMajor >= 17 // VS 2012
+
+ var linkerPath = effectiveLinkerPath(product, inputs);
+ var useCompilerDriver = linkerPath === product.cpp.compilerPath;
+ // args variable is built as follows:
+ // [linkerWrapper] linkerPath /nologo [driverFlags driverLinkerFlags]
+ // allInputs libDeps [/link] linkerArgs
+ var args = []
+
+ if (useCompilerDriver) {
+ args.push('/nologo');
+ var driverFlags = product.cpp.driverFlags;
+ if (driverFlags)
+ args = args.concat(driverFlags);
+ var driverLinkerFlags = product.cpp.driverLinkerFlags;
+ if (driverLinkerFlags)
+ args = args.concat(driverLinkerFlags);
+ }
+
+ var allInputs = inputs.obj || [];
+ for (i in allInputs) {
+ var fileName = FileInfo.toWindowsSeparators(allInputs[i].filePath)
+ args.push(fileName)
+ }
- var args = ['/nologo']
+ var linkerArgs = ['/nologo']
if (linkDLL) {
- args.push('/DLL');
- args.push('/IMPLIB:' + FileInfo.toWindowsSeparators(outputs.dynamiclibrary_import[0].filePath));
+ linkerArgs.push('/DLL');
+ linkerArgs.push('/IMPLIB:' + FileInfo.toWindowsSeparators(outputs.dynamiclibrary_import[0].filePath));
}
if (debugInformation) {
- args.push("/DEBUG");
+ linkerArgs.push("/DEBUG");
var debugInfo = outputs.debuginfo_app || outputs.debuginfo_dll;
if (debugInfo)
- args.push("/PDB:" + debugInfo[0].fileName);
+ linkerArgs.push("/PDB:" + debugInfo[0].fileName);
} else {
- args.push('/INCREMENTAL:NO')
+ linkerArgs.push('/INCREMENTAL:NO')
}
switch (product.qbs.architecture) {
case "x86":
- args.push("/MACHINE:X86");
+ linkerArgs.push("/MACHINE:X86");
break;
case "x86_64":
- args.push("/MACHINE:X64");
+ linkerArgs.push("/MACHINE:X64");
break;
case "ia64":
- args.push("/MACHINE:IA64");
+ linkerArgs.push("/MACHINE:IA64");
break;
case "armv7":
- args.push("/MACHINE:ARM");
+ linkerArgs.push("/MACHINE:ARM");
break;
case "arm64":
- args.push("/MACHINE:ARM64");
+ linkerArgs.push("/MACHINE:ARM64");
break;
}
+ if (useCompilerDriver)
+ handleClangClArchitectureFlags(product, product.qbs.architecture, args);
+
var requireAppContainer = product.cpp.requireAppContainer;
if (requireAppContainer !== undefined)
- args.push("/APPCONTAINER" + (requireAppContainer ? "" : ":NO"));
+ linkerArgs.push("/APPCONTAINER" + (requireAppContainer ? "" : ":NO"));
var minimumWindowsVersion = product.cpp.minimumWindowsVersion;
var subsystemSwitch = undefined;
@@ -415,27 +466,29 @@ function prepareLinker(project, product, inputs, outputs, input, output) {
subsystemSwitch = product.consoleApplication === false ? '/SUBSYSTEM:WINDOWS' : '/SUBSYSTEM:CONSOLE';
}
- var useLldLink = product.cpp.linkerName === "lld-link.exe";
+ var useLldLink = useCompilerDriver && product.cpp.linkerVariant === "lld"
+ || !useCompilerDriver && product.cpp.linkerName === "lld-link.exe";
if (minimumWindowsVersion) {
var subsystemVersion = WindowsUtils.getWindowsVersionInFormat(minimumWindowsVersion,
'subsystem');
if (subsystemVersion) {
subsystemSwitch += ',' + subsystemVersion;
- if (!useLldLink) // llvm linker does not support /OSVERSION
- args.push('/OSVERSION:' + subsystemVersion);
+ // llvm linker does not support /OSVERSION
+ if (!useLldLink)
+ linkerArgs.push('/OSVERSION:' + subsystemVersion);
}
}
if (subsystemSwitch)
- args.push(subsystemSwitch);
+ linkerArgs.push(subsystemSwitch);
var linkerOutputNativeFilePath = FileInfo.toWindowsSeparators(primaryOutput.filePath);
var manifestFileNames = [];
if (generateManifestFiles) {
if (canEmbedManifest) {
- args.push("/MANIFEST:embed");
+ linkerArgs.push("/MANIFEST:embed");
additionalManifestInputs.forEach(function (manifestFileName) {
- args.push("/MANIFESTINPUT:" + manifestFileName);
+ linkerArgs.push("/MANIFESTINPUT:" + manifestFileName);
});
} else {
linkerOutputNativeFilePath
@@ -444,17 +497,11 @@ function prepareLinker(project, product, inputs, outputs, input, output) {
+ primaryOutput.fileName);
var manifestFileName = linkerOutputNativeFilePath + ".manifest";
- args.push('/MANIFEST', '/MANIFESTFILE:' + manifestFileName);
+ linkerArgs.push('/MANIFEST', '/MANIFESTFILE:' + manifestFileName);
manifestFileNames = [manifestFileName].concat(additionalManifestInputs);
}
}
- var allInputs = inputs.obj || [];
- for (i in allInputs) {
- var fileName = FileInfo.toWindowsSeparators(allInputs[i].filePath)
- args.push(fileName)
- }
-
var wholeArchiveSupported = linkerSupportsWholeArchive(product);
var wholeArchiveRequested = false;
var libDeps = collectLibraryDependencies(product);
@@ -465,8 +512,16 @@ function prepareLinker(project, product, inputs, outputs, input, output) {
if (lib === prevLib)
continue;
prevLib = lib;
- args.push((wholeArchiveSupported && dep.wholeArchive ? "/WHOLEARCHIVE:" : "")
- + FileInfo.toWindowsSeparators(lib));
+
+ if (wholeArchiveSupported && dep.wholeArchive) {
+ // need to pass libraries to the driver to avoid "no input files" error if no object
+ // files are specified; thus libraries are duplicated when using "WHOLEARCHIVE"
+ if (useCompilerDriver && allInputs.length === 0)
+ args.push(FileInfo.toWindowsSeparators(lib));
+ linkerArgs.push("/WHOLEARCHIVE:" + FileInfo.toWindowsSeparators(lib));
+ } else {
+ args.push(FileInfo.toWindowsSeparators(lib));
+ }
if (dep.wholeArchive)
wholeArchiveRequested = true;
}
@@ -477,34 +532,36 @@ function prepareLinker(project, product, inputs, outputs, input, output) {
}
if (product.cpp.entryPoint)
- args.push("/ENTRY:" + product.cpp.entryPoint);
+ linkerArgs.push("/ENTRY:" + product.cpp.entryPoint);
if (outputs.application && product.cpp.generateLinkerMapFile) {
if (useLldLink)
- args.push("/lldmap:" + outputs.mem_map[0].filePath);
+ linkerArgs.push("/lldmap:" + outputs.mem_map[0].filePath);
else
- args.push("/MAP:" + outputs.mem_map[0].filePath);
+ linkerArgs.push("/MAP:" + outputs.mem_map[0].filePath);
}
- args.push('/OUT:' + linkerOutputNativeFilePath)
+ if (useCompilerDriver)
+ args.push('/Fe' + linkerOutputNativeFilePath);
+ else
+ linkerArgs.push('/OUT:' + linkerOutputNativeFilePath);
var libraryPaths = product.cpp.libraryPaths;
if (libraryPaths)
libraryPaths = [].uniqueConcat(libraryPaths);
for (i in libraryPaths) {
- args.push('/LIBPATH:' + FileInfo.toWindowsSeparators(libraryPaths[i]))
+ linkerArgs.push('/LIBPATH:' + FileInfo.toWindowsSeparators(libraryPaths[i]))
}
- handleDiscardProperty(product, args);
+ handleDiscardProperty(product, linkerArgs);
var linkerFlags = product.cpp.platformLinkerFlags.concat(product.cpp.linkerFlags);
- args = args.concat(linkerFlags);
+ linkerArgs = linkerArgs.concat(linkerFlags);
if (product.cpp.allowUnresolvedSymbols)
- args.push("/FORCE:UNRESOLVED");
+ linkerArgs.push("/FORCE:UNRESOLVED");
- var linkerPath = product.cpp.linkerPath;
var wrapperArgs = product.cpp.linkerWrapper;
if (wrapperArgs && wrapperArgs.length > 0) {
- args.unshift(linkerPath);
+ linkerArgs.unshift(linkerPath);
linkerPath = wrapperArgs.shift();
- args = wrapperArgs.concat(args);
+ linkerArgs = wrapperArgs.concat(linkerArgs);
}
var commands = [];
var warningCmd = new JavaScriptCommand();
@@ -522,6 +579,10 @@ function prepareLinker(project, product, inputs, outputs, input, output) {
}
};
commands.push(warningCmd);
+
+ if (linkerArgs.length !== 0)
+ args = args.concat(useCompilerDriver ? ['/link'] : []).concat(linkerArgs);
+
var cmd = new Command(linkerPath, args)
cmd.description = 'linking ' + primaryOutput.fileName;
cmd.highlight = 'linker';
@@ -529,6 +590,7 @@ function prepareLinker(project, product, inputs, outputs, input, output) {
cmd.relevantEnvironmentVariables = ["LINK", "_LINK_", "LIB", "TMP"];
cmd.workingDirectory = FileInfo.path(primaryOutput.filePath)
cmd.responseFileUsagePrefix = '@';
+ cmd.responseFileSeparator = useCompilerDriver ? ' ' : '\n';
cmd.stdoutFilterFunction = function(output) {
res = output.replace(/^.*performing full link.*\s*/, "");
return res.replace(/^ *Creating library.*\r\n$/, "");
diff --git a/share/qbs/modules/cpp/windows-clang-cl.qbs b/share/qbs/modules/cpp/windows-clang-cl.qbs
index 1b2833060..2ac3f356a 100644
--- a/share/qbs/modules/cpp/windows-clang-cl.qbs
+++ b/share/qbs/modules/cpp/windows-clang-cl.qbs
@@ -65,6 +65,17 @@ MsvcBaseModule {
: undefined
buildEnv: clangClProbe.buildEnv
+ property string linkerVariant
+ PropertyOptions {
+ name: "linkerVariant"
+ allowedValues: ["lld", "link"]
+ description: "Allows to specify the linker variant. Maps to clang-cl's -fuse-ld option."
+ }
+ Properties {
+ condition: linkerVariant
+ driverLinkerFlags: "-fuse-ld=" + linkerVariant
+ }
+
property string vcvarsallPath
compilerName: "clang-cl.exe"