aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDenis Shienkov <denis.shienkov@gmail.com>2020-05-19 18:44:02 +0300
committerDenis Shienkov <denis.shienkov@gmail.com>2020-05-26 08:38:33 +0000
commit25bbd9f0d6877a8f6b245708f6cfdfd5472ea0ff (patch)
tree8e8e09b5bd6684ffbacad32f3672504e35dbc115
parent495d7767af801c6d7cda0d759b89a18f490359f2 (diff)
Msvc: Handle windows module definition file
Module-definition (.def) file provide the linker with information about exports, attributes, and other information about the program to be linked. This file can be used instead of e.g. __declspec(dllexport) keywords inside of a header files to export an appropriate symbols: * https://docs.microsoft.com/en-us/cpp/build/reference/module-definition-dot-def-files?view=vs-2019 * https://docs.microsoft.com/en-us/cpp/build/reference/def-specify-module-definition-file?view=vs-2019 To make it supported, we have created the additional 'def' file tag, and now we can add the required module-definition file to the {Product|Group}'s 'files' property. Fixes: QBS-571 Change-Id: I831d2e1b8f9f061a4414a5eaac85b71584f48c5d Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
-rw-r--r--doc/reference/modules/cpp-module.qdoc8
-rw-r--r--share/qbs/modules/cpp/msvc.js9
-rw-r--r--share/qbs/modules/cpp/windows-msvc-base.qbs9
-rw-r--r--tests/auto/blackbox/testdata/linker-module-definition/linker-module-definition.qbs20
-rw-r--r--tests/auto/blackbox/testdata/linker-module-definition/testapp.cpp39
-rw-r--r--tests/auto/blackbox/testdata/linker-module-definition/testlib.cpp41
-rw-r--r--tests/auto/blackbox/testdata/linker-module-definition/testlib.def3
-rw-r--r--tests/auto/blackbox/tst_blackbox.cpp20
-rw-r--r--tests/auto/blackbox/tst_blackbox.h1
9 files changed, 148 insertions, 2 deletions
diff --git a/doc/reference/modules/cpp-module.qdoc b/doc/reference/modules/cpp-module.qdoc
index ff8c0172e..3c1744e09 100644
--- a/doc/reference/modules/cpp-module.qdoc
+++ b/doc/reference/modules/cpp-module.qdoc
@@ -144,6 +144,14 @@
and Objective-C++, respectively. There can be only one such file per product and
language.
\row
+ \li \c{"def"}
+ \li -
+ \li 1.17.0
+ \li This tag is used for a module-definition file (.def) to be passed to the linker.
+ Such a file provides the linker with information about exports, attributes,
+ and other information about the program to be linked. This file tag only has
+ an effect with the MSVC toolchain.
+ \row
\li \c{"dynamiclibrary"}
\li n/a
\li 1.0.1
diff --git a/share/qbs/modules/cpp/msvc.js b/share/qbs/modules/cpp/msvc.js
index c06286cbe..8611ebe50 100644
--- a/share/qbs/modules/cpp/msvc.js
+++ b/share/qbs/modules/cpp/msvc.js
@@ -391,6 +391,10 @@ function prepareLinker(project, product, inputs, outputs, input, output) {
function (a) {
return a.filePath;
});
+ var moduleDefinitionInputs = Array.prototype.map.call(inputs["def"],
+ function (a) {
+ return a.filePath;
+ });
var generateManifestFiles = !linkDLL && product.cpp.generateManifestFile;
var useClangCl = product.qbs.toolchain.contains("clang-cl");
var canEmbedManifest = useClangCl || product.cpp.compilerVersionMajor >= 17 // VS 2012
@@ -502,6 +506,11 @@ function prepareLinker(project, product, inputs, outputs, input, output) {
}
}
+ if (moduleDefinitionInputs.length === 1)
+ linkerArgs.push("/DEF:" + moduleDefinitionInputs[0]);
+ else if (moduleDefinitionInputs.length > 1)
+ throw new Error("Only one '.def' file can be specified for linking");
+
var wholeArchiveSupported = linkerSupportsWholeArchive(product);
var wholeArchiveRequested = false;
var libDeps = collectLibraryDependencies(product);
diff --git a/share/qbs/modules/cpp/windows-msvc-base.qbs b/share/qbs/modules/cpp/windows-msvc-base.qbs
index aa1c8256c..34132ac49 100644
--- a/share/qbs/modules/cpp/windows-msvc-base.qbs
+++ b/share/qbs/modules/cpp/windows-msvc-base.qbs
@@ -170,10 +170,15 @@ CppModule {
fileTags: ["native.pe.manifest"]
}
+ FileTagger {
+ patterns: ["*.def"]
+ fileTags: ["def"]
+ }
+
Rule {
name: "applicationLinker"
multiplex: true
- inputs: ['obj', 'native.pe.manifest']
+ inputs: ['obj', 'native.pe.manifest', 'def']
inputsFromDependencies: ['staticlibrary', 'dynamiclibrary_import', "debuginfo_app"]
outputFileTags: ["application", "debuginfo_app", "mem_map"]
@@ -211,7 +216,7 @@ CppModule {
Rule {
name: "dynamicLibraryLinker"
multiplex: true
- inputs: ['obj', 'native.pe.manifest']
+ inputs: ['obj', 'native.pe.manifest', 'def']
inputsFromDependencies: ['staticlibrary', 'dynamiclibrary_import', "debuginfo_dll"]
outputFileTags: ["dynamiclibrary", "dynamiclibrary_import", "debuginfo_dll"]
diff --git a/tests/auto/blackbox/testdata/linker-module-definition/linker-module-definition.qbs b/tests/auto/blackbox/testdata/linker-module-definition/linker-module-definition.qbs
new file mode 100644
index 000000000..519b6e065
--- /dev/null
+++ b/tests/auto/blackbox/testdata/linker-module-definition/linker-module-definition.qbs
@@ -0,0 +1,20 @@
+import qbs
+
+Project {
+ condition: {
+ var result = qbs.targetPlatform === qbs.hostPlatform;
+ if (!result)
+ console.info("targetPlatform differs from hostPlatform");
+ return result;
+ }
+ DynamicLibrary {
+ name: "testlib"
+ Depends { name: "cpp"}
+ files: ["testlib.cpp", "testlib.def"]
+ }
+ CppApplication {
+ name: "testapp"
+ Depends { name: "testlib"}
+ files: ["testapp.cpp"]
+ }
+}
diff --git a/tests/auto/blackbox/testdata/linker-module-definition/testapp.cpp b/tests/auto/blackbox/testdata/linker-module-definition/testapp.cpp
new file mode 100644
index 000000000..7cb5ee901
--- /dev/null
+++ b/tests/auto/blackbox/testdata/linker-module-definition/testapp.cpp
@@ -0,0 +1,39 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+extern void foo();
+extern void bar();
+
+int main()
+{
+ foo();
+ bar();
+ return 0;
+}
diff --git a/tests/auto/blackbox/testdata/linker-module-definition/testlib.cpp b/tests/auto/blackbox/testdata/linker-module-definition/testlib.cpp
new file mode 100644
index 000000000..d1cfc253a
--- /dev/null
+++ b/tests/auto/blackbox/testdata/linker-module-definition/testlib.cpp
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: http://www.qt.io/licensing
+**
+** This file is part of Qbs.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms and
+** conditions see http://www.qt.io/terms-conditions. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include <cstdio>
+
+void foo()
+{
+ printf("foo\n");
+}
+
+void bar()
+{
+ printf("bar\n");
+}
diff --git a/tests/auto/blackbox/testdata/linker-module-definition/testlib.def b/tests/auto/blackbox/testdata/linker-module-definition/testlib.def
new file mode 100644
index 000000000..36967ddd5
--- /dev/null
+++ b/tests/auto/blackbox/testdata/linker-module-definition/testlib.def
@@ -0,0 +1,3 @@
+EXPORTS
+foo
+bar
diff --git a/tests/auto/blackbox/tst_blackbox.cpp b/tests/auto/blackbox/tst_blackbox.cpp
index 8693aaa48..912208093 100644
--- a/tests/auto/blackbox/tst_blackbox.cpp
+++ b/tests/auto/blackbox/tst_blackbox.cpp
@@ -5000,6 +5000,26 @@ void TestBlackbox::linkerScripts()
"TEST_SYMBOL_FROM_RECURSIVE_MODIFIED"}));
}
+void TestBlackbox::linkerModuleDefinition()
+{
+ QDir::setCurrent(testDataDir + "/linker-module-definition");
+ QCOMPARE(runQbs({"build"}), 0);
+ if (m_qbsStdout.contains("targetPlatform differs from hostPlatform"))
+ QSKIP("Cannot run binaries in cross-compiled build");
+ QCOMPARE(runQbs({"run"}), 0);
+ const auto verifyOutput = [this](const QByteArrayList &symbols) {
+ for (const QByteArray &symbol : symbols) {
+ if (!m_qbsStdout.contains(symbol)) {
+ qDebug() << "Expected symbol" << symbol
+ << "not found in" << m_qbsStdout;
+ return false;
+ }
+ }
+ return true;
+ };
+ QVERIFY(verifyOutput({"foo", "bar"}));
+}
+
void TestBlackbox::listProducts()
{
QDir::setCurrent(testDataDir + "/list-products");
diff --git a/tests/auto/blackbox/tst_blackbox.h b/tests/auto/blackbox/tst_blackbox.h
index 757462b80..7aa397c1e 100644
--- a/tests/auto/blackbox/tst_blackbox.h
+++ b/tests/auto/blackbox/tst_blackbox.h
@@ -181,6 +181,7 @@ private slots:
void linkerLibraryDuplicates();
void linkerLibraryDuplicates_data();
void linkerScripts();
+ void linkerModuleDefinition();
void listProducts();
void listPropertiesWithOuter();
void listPropertyOrder();