diff options
author | Denis Shienkov <denis.shienkov@gmail.com> | 2020-05-19 18:44:02 +0300 |
---|---|---|
committer | Denis Shienkov <denis.shienkov@gmail.com> | 2020-05-26 08:38:33 +0000 |
commit | 25bbd9f0d6877a8f6b245708f6cfdfd5472ea0ff (patch) | |
tree | 8e8e09b5bd6684ffbacad32f3672504e35dbc115 | |
parent | 495d7767af801c6d7cda0d759b89a18f490359f2 (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>
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(); |