aboutsummaryrefslogtreecommitdiffstats
path: root/share
diff options
context:
space:
mode:
authorDenis Shienkov <denis.shienkov@gmail.com>2021-07-07 17:29:42 +0300
committerDenis Shienkov <denis.shienkov@gmail.com>2021-07-27 08:18:11 +0000
commitae1368529849bcad0d7d524ae9396c4205209322 (patch)
treeb520209a486da0b2f03e3f8fb170a0934f21a37c /share
parent08782fcc1002e8a6722cdc3d1b9912d01413805d (diff)
Long live Digital Mars toolchain
This patch adds an experimental support for the Digital Mars C/C++ compiler for Windows: * https://www.digitalmars.com/ This compiler is only distributed for Windows host platform, but allows to create the binaries for Win32, Win16, DOS32 and DOS targets. This patch implements only the Win32 targets and has the following limitations: * Support for precompiled headers is not implemented yet (but which is supported by the compiler). * There is no support for the CI autotests due to the fact that the compiler has the following restrictions: - it needs a separate masm386 assembler. - it needs a special format of DLL library sources (required the DLL main function). - it needs the `kernel32.lib` to be always explicitly linked. - and, maybe other unexpected stuff. The following features are currently supported: * Compiling a source files in the C or the C++ mode. * Compiling the source resource (RC) files. * Creation of an applications (both console and GUI). * Creation of an dynamic (DLL) libraries with its import files. * Creation of a static libraries. Task-number: QBS-1598 Change-Id: I5a6ac05a7e7513a1c6d2403db037c309b0f12b90 Reviewed-by: Ivan Komissarov <ABBAPOH@gmail.com>
Diffstat (limited to 'share')
-rw-r--r--share/qbs/imports/qbs/Probes/DmcProbe.qbs89
-rw-r--r--share/qbs/modules/cpp/CppModule.qbs1
-rw-r--r--share/qbs/modules/cpp/cpp.js105
-rw-r--r--share/qbs/modules/cpp/dmc.js462
-rw-r--r--share/qbs/modules/cpp/dmc.qbs177
5 files changed, 814 insertions, 20 deletions
diff --git a/share/qbs/imports/qbs/Probes/DmcProbe.qbs b/share/qbs/imports/qbs/Probes/DmcProbe.qbs
new file mode 100644
index 000000000..0375805b5
--- /dev/null
+++ b/share/qbs/imports/qbs/Probes/DmcProbe.qbs
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 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.
+**
+****************************************************************************/
+
+import qbs.File
+import qbs.ModUtils
+import "../../../modules/cpp/dmc.js" as DMC
+
+PathProbe {
+ // Inputs
+ property string compilerFilePath
+ property stringList enableDefinesByLanguage
+
+ // Outputs
+ property string architecture
+ property string targetPlatform
+ property int versionMajor
+ property int versionMinor
+ property int versionPatch
+ property stringList includePaths
+ property var compilerDefinesByLanguage
+
+ configure: {
+ compilerDefinesByLanguage = {};
+
+ if (!File.exists(compilerFilePath)) {
+ found = false;
+ return;
+ }
+
+ var languages = enableDefinesByLanguage;
+ if (!languages || languages.length === 0)
+ languages = ["c"];
+
+ var defaultPathsByLanguage = {};
+ for (var i = 0; i < languages.length; ++i) {
+ var tag = languages[i];
+ compilerDefinesByLanguage[tag] = DMC.dumpMacros(
+ compilerFilePath, tag);
+ var paths = DMC.dumpDefaultPaths(compilerFilePath, tag);
+ defaultPathsByLanguage[tag] = paths;
+ }
+
+ var macros = compilerDefinesByLanguage["c"]
+ || compilerDefinesByLanguage["cpp"];
+
+ architecture = ModUtils.guessArchitecture(macros);
+ targetPlatform = ModUtils.guessTargetPlatform(macros);
+
+ var defaultPaths = defaultPathsByLanguage["cpp"]
+ || defaultPathsByLanguage["c"];
+
+ includePaths = defaultPaths.includePaths;
+
+ var version = DMC.guessVersion(macros);
+ if (version) {
+ versionMajor = version.major;
+ versionMinor = version.minor;
+ versionPatch = version.patch;
+ found = !!architecture && !!endianness;
+ }
+ }
+}
diff --git a/share/qbs/modules/cpp/CppModule.qbs b/share/qbs/modules/cpp/CppModule.qbs
index 17c8c6bfc..0a959ea8e 100644
--- a/share/qbs/modules/cpp/CppModule.qbs
+++ b/share/qbs/modules/cpp/CppModule.qbs
@@ -190,6 +190,7 @@ Module {
property string linkerMapSuffix: ".map"
property string compilerListingSuffix: ".lst"
property string assemblerListingSuffix: ".lst"
+ property string resourceSuffix: ".res"
property bool createSymlinks: true
property stringList dynamicLibraries // list of names, will be linked with -lname
property stringList staticLibraries // list of static library files
diff --git a/share/qbs/modules/cpp/cpp.js b/share/qbs/modules/cpp/cpp.js
index 1e153e8ba..9563a5c84 100644
--- a/share/qbs/modules/cpp/cpp.js
+++ b/share/qbs/modules/cpp/cpp.js
@@ -28,6 +28,7 @@
**
****************************************************************************/
+var File = require("qbs.File");
var FileInfo = require("qbs.FileInfo");
var ModUtils = require("qbs.ModUtils");
var PathTools = require("qbs.PathTools");
@@ -63,6 +64,12 @@ function extractMacros(output) {
return m;
}
+function relativePath(baseDirectory, filePath) {
+ if (FileInfo.isAbsolutePath(filePath))
+ return FileInfo.relativePath(baseDirectory, filePath);
+ return filePath;
+}
+
function assemblerOutputTags(needsListingFiles) {
var tags = ["obj"];
if (needsListingFiles)
@@ -84,10 +91,18 @@ function applicationLinkerOutputTags(needsLinkerMapFile) {
return tags;
}
+function dynamicLibraryLinkerOutputTags() {
+ return ["dynamiclibrary", "dynamiclibrary_import"];
+}
+
function staticLibraryLinkerOutputTags() {
return ["staticlibrary"];
}
+function resourceCompilerOutputTags() {
+ return ["res"];
+}
+
function assemblerOutputArtifacts(input) {
var artifacts = [];
artifacts.push({
@@ -140,32 +155,57 @@ function applicationLinkerOutputArtifacts(product) {
return artifacts;
}
+function dynamicLibraryLinkerOutputArtifacts(product) {
+ return [{
+ fileTags: ["dynamiclibrary"],
+ filePath: FileInfo.joinPaths(product.destinationDirectory,
+ PathTools.dynamicLibraryFilePath(product))
+ }, {
+ fileTags: ["dynamiclibrary_import"],
+ filePath: FileInfo.joinPaths(product.destinationDirectory,
+ PathTools.importLibraryFilePath(product)),
+ alwaysUpdated: false
+ }];
+}
+
function staticLibraryLinkerOutputArtifacts(product) {
- var staticLib = {
+ return [{
fileTags: ["staticlibrary"],
- filePath: FileInfo.joinPaths(
- product.destinationDirectory,
- PathTools.staticLibraryFilePath(product))
- };
- return [staticLib]
+ filePath: FileInfo.joinPaths(product.destinationDirectory,
+ PathTools.staticLibraryFilePath(product))
+ }];
+}
+
+function resourceCompilerOutputArtifacts(input) {
+ return [{
+ fileTags: ["res"],
+ filePath: FileInfo.joinPaths(Utilities.getHash(input.baseDir),
+ input.completeBaseName + input.cpp.resourceSuffix)
+ }];
}
function collectLibraryDependencies(product) {
var seen = {};
var result = [];
- function addFilePath(filePath) {
- result.push({ filePath: filePath });
+ function addFilePath(filePath, wholeArchive, productName) {
+ result.push({ filePath: filePath, wholeArchive: wholeArchive, productName: productName });
}
function addArtifactFilePaths(dep, artifacts) {
if (!artifacts)
return;
var artifactFilePaths = artifacts.map(function(a) { return a.filePath; });
- artifactFilePaths.forEach(addFilePath);
+ var wholeArchive = dep.parameters.cpp && dep.parameters.cpp.linkWholeArchive;
+ var artifactsAreImportLibs = artifacts.length > 0
+ && artifacts[0].fileTags.contains("dynamiclibrary_import");
+ for (var i = 0; i < artifactFilePaths.length; ++i) {
+ addFilePath(artifactFilePaths[i], wholeArchive,
+ artifactsAreImportLibs ? dep.name : undefined);
+ }
}
- function addExternalStaticLibs(obj) {
+ function addExternalLibs(obj) {
if (!obj.cpp)
return;
function ensureArray(a) {
@@ -175,36 +215,57 @@ function collectLibraryDependencies(product) {
return ensureArray(ModUtils.sanitizedModuleProperty(obj, moduleName, propertyName));
}
var externalLibs = [].concat(
- sanitizedModuleListProperty(obj, "cpp", "staticLibraries"));
- var staticLibrarySuffix = obj.moduleProperty("cpp", "staticLibrarySuffix");
- externalLibs.forEach(function(staticLibraryName) {
- if (!staticLibraryName.endsWith(staticLibrarySuffix))
- staticLibraryName += staticLibrarySuffix;
- addFilePath(staticLibraryName);
+ sanitizedModuleListProperty(obj, "cpp", "staticLibraries"),
+ sanitizedModuleListProperty(obj, "cpp", "dynamicLibraries"));
+ var libSuffix = obj.moduleProperty("cpp", "staticLibrarySuffix");
+ externalLibs.forEach(function(libName) {
+ if (!libName.endsWith(libSuffix) && !libName.startsWith('@'))
+ libName += libSuffix;
+ addFilePath(libName);
});
}
function traverse(dep) {
if (seen.hasOwnProperty(dep.name))
return;
- seen[dep.name] = true;
-
if (dep.parameters.cpp && dep.parameters.cpp.link === false)
return;
var staticLibraryArtifacts = dep.artifacts["staticlibrary"];
+ var dynamicLibraryArtifacts = staticLibraryArtifacts
+ ? null : dep.artifacts["dynamiclibrary_import"];
if (staticLibraryArtifacts) {
+ seen[dep.name] = true;
dep.dependencies.forEach(traverse);
addArtifactFilePaths(dep, staticLibraryArtifacts);
- addExternalStaticLibs(dep);
+ addExternalLibs(dep);
+ } else if (dynamicLibraryArtifacts) {
+ seen[dep.name] = true;
+ addArtifactFilePaths(dep, dynamicLibraryArtifacts);
}
}
product.dependencies.forEach(traverse);
- addExternalStaticLibs(product);
+ addExternalLibs(product);
return result;
}
+function collectAbsoluteLibraryDependencyPaths(product) {
+ var paths = collectLibraryPaths(product);
+ var deps = collectLibraryDependencies(product);
+ return deps.map(function(dep) {
+ var filePath = dep.filePath;
+ if (FileInfo.isAbsolutePath(filePath))
+ return filePath;
+ for (var i = 0; i < paths.length; ++i) {
+ var fullPath = FileInfo.joinPaths(paths[i], filePath);
+ if (File.exists(fullPath))
+ return fullPath;
+ }
+ return filePath;
+ });
+}
+
function collectDefines(input) {
var allDefines = [];
var platformDefines = input.cpp.platformDefines;
@@ -260,6 +321,10 @@ function collectLinkerObjectPaths(inputs) {
return inputs.obj ? inputs.obj.map(function(obj) { return obj.filePath; }) : [];
}
+function collectResourceObjectPaths(inputs) {
+ return inputs.res ? inputs.res.map(function(res) { return res.filePath; }) : [];
+}
+
function collectLibraryDependenciesArguments(product) {
var deps = collectLibraryDependencies(product);
return deps.map(function(dep) { return product.cpp.libraryDependencyFlag + dep.filePath })
diff --git a/share/qbs/modules/cpp/dmc.js b/share/qbs/modules/cpp/dmc.js
new file mode 100644
index 000000000..7303c67fc
--- /dev/null
+++ b/share/qbs/modules/cpp/dmc.js
@@ -0,0 +1,462 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 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.
+**
+****************************************************************************/
+
+var Cpp = require("cpp.js");
+var Environment = require("qbs.Environment");
+var File = require("qbs.File");
+var FileInfo = require("qbs.FileInfo");
+var ModUtils = require("qbs.ModUtils");
+var Process = require("qbs.Process");
+var TemporaryDir = require("qbs.TemporaryDir");
+var TextFile = require("qbs.TextFile");
+var Utilities = require("qbs.Utilities");
+
+function dumpMacros(compilerFilePath, tag) {
+ // Note: The DMC compiler does not support the predefined/ macros dumping. So, we do it
+ // with the following trick, where we try to create and compile a special temporary file
+ // and to parse the console output with the own magic pattern: #define <key> <value>.
+
+ var outputDirectory = new TemporaryDir();
+ var outputFilePath = FileInfo.joinPaths(outputDirectory.path(), "dump-macros.c");
+ var outputFile = new TextFile(outputFilePath, TextFile.WriteOnly);
+ outputFile.writeLine("#define VALUE_TO_STRING(x) #x");
+ outputFile.writeLine("#define VALUE(x) VALUE_TO_STRING(x)");
+ outputFile.writeLine("#define VAR_NAME_VALUE(var) \"#define \" #var\" \"VALUE(var)");
+ // Declare all available pre-defined macros of DMC compiler.
+ var keys = [
+ // Prepare the DOS target macros.
+ "_MSDOS", "MSDOS",
+ // Prepare the OS/2 target macros.
+ "__OS2__",
+ "WIN32", "_WIN32",
+ // Prepare extended the 32 and 16 bit DOS target macros.
+ "DOS386", "DOS16RM",
+ // Prepare the memory model macros.
+ "M_I86", "_M_I86",
+ "_M_I86TM", "M_I86TM",
+ "_M_I86SM", "M_I86SM",
+ "_M_I86MM", "M_I86MM",
+ "_M_I86CM", "M_I86CM",
+ "_M_I86LM", "M_I86LM",
+ "_M_I86VM", "M_I86VM",
+ // Prepare 8086 macros.
+ "_M_I8086", "M_I8086",
+ // Prepare 286 macros.
+ "_M_I286", "M_I286",
+ // Prepare 32 bit macros.
+ "_M_IX86",
+ // Prepare compiler identification macros.
+ "__DMC__", "__DMC_VERSION_STRING__",
+ // Prepare common compiler macros.
+ "_CHAR_UNSIGNED", "_CHAR_EQ_UCHAR", "_DEBUG_TRACE", "_DLL",
+ "_ENABLE_ARRAYNEW", "_BOOL_DEFINED", "_WCHAR_T_DEFINED",
+ "_CPPRTTI", "_CPPUNWIND", "_MD", "_PUSHPOP_SUPPORTED",
+ "_STDCALL_SUPPORTED", "__INTSIZE", "__DEFALIGN", "_INTEGRAL_MAX_BITS",
+ "_WINDOWS", "_WINDLL", "__INLINE_8087", "__I86__", "__SMALL__",
+ "__MEDIUM__", "__COMPACT__", "__LARGE__", "__VCM__", "__FPCE__",
+ "__FPCE__IEEE__", "DEBUG",
+ // Prepare C99 and C++98 macros.
+ "__STDC__", "__STDC_HOSTED__", "__STDC_VERSION__", "__STDC_IEC_559__",
+ "__STDC_IEC_559_COMPLEX__", "__STDC_ISO_10646__", "__cplusplus"
+ ];
+ for (var i = 0; i < keys.length; ++i) {
+ var key = keys[i];
+ outputFile.writeLine("#if defined (" + key + ")");
+ outputFile.writeLine("#pragma message (VAR_NAME_VALUE(" + key + "))");
+ outputFile.writeLine("#endif");
+ }
+ outputFile.close();
+
+ var process = new Process();
+ process.setWorkingDirectory(outputDirectory.path());
+ var args = ["-c"].concat((tag === "cpp") ? ["-cpp"] : [],
+ FileInfo.toWindowsSeparators(outputFilePath));
+ process.exec(compilerFilePath, args, false);
+ File.remove(outputFilePath);
+ var out = process.readStdOut();
+ return Cpp.extractMacros(out);
+}
+
+function dumpDefaultPaths(compilerFilePath, tag) {
+ var binPath = FileInfo.path(compilerFilePath);
+ var rootPath = FileInfo.path(binPath);
+ var includePaths = [];
+ var cppIncludePath = FileInfo.joinPaths(rootPath, "stlport/stlport");
+ if (File.exists(cppIncludePath))
+ includePaths.push(cppIncludePath);
+ var cIncludePath = FileInfo.joinPaths(rootPath, "include");
+ if (File.exists(cIncludePath))
+ includePaths.push(cIncludePath);
+
+ var libraryPaths = [];
+ var libraryPath = FileInfo.joinPaths(rootPath, "lib");
+ if (File.exists(libraryPath))
+ libraryPaths.push(libraryPath);
+
+ return {
+ "includePaths": includePaths,
+ "libraryPaths": libraryPaths,
+ }
+}
+
+function guessVersion(macros) {
+ var version = macros["__DMC__"];
+ return { major: parseInt(version / 100),
+ minor: parseInt(version % 100),
+ patch: 0 };
+}
+
+function effectiveLinkerPath(product) {
+ if (product.cpp.linkerMode === "automatic") {
+ var compilerPath = product.cpp.compilerPath;
+ if (compilerPath)
+ return compilerPath;
+ console.log("Found no C-language objects, choosing system linker for " + product.name);
+ }
+ return product.cpp.linkerPath;
+}
+
+function useCompilerDriverLinker(product) {
+ var linker = effectiveLinkerPath(product);
+ var compilers = product.cpp.compilerPathByLanguage;
+ if (compilers)
+ return linker === compilers["cpp"] || linker === compilers["c"];
+ return linker === product.cpp.compilerPath;
+}
+
+function depsOutputTags() {
+ return ["dep"];
+}
+
+function depsOutputArtifacts(input, product) {
+ return [{
+ fileTags: depsOutputTags(),
+ filePath: FileInfo.joinPaths(product.destinationDirectory,
+ input.baseName + ".dep")
+ }];
+}
+
+function compilerFlags(project, product, input, outputs, explicitlyDependsOn) {
+ var args = ["-c"];
+
+ // Input.
+ args.push(FileInfo.toWindowsSeparators(input.filePath));
+ // Output.
+ args.push("-o" + FileInfo.toWindowsSeparators(outputs.obj[0].filePath));
+ // Preinclude headers.
+ args = args.concat(Cpp.collectPreincludePaths(input).map(function(path) {
+ return input.cpp.preincludeFlag + FileInfo.toWindowsSeparators(path);
+ }));
+
+ // Defines.
+ args = args.concat(Cpp.collectDefinesArguments(input));
+
+ var tag = ModUtils.fileTagForTargetLanguage(input.fileTags.concat(outputs.obj[0].fileTags));
+ if (tag === "cpp") {
+ // We need to add the paths to the STL includes, because the DMC compiler does
+ // not handle it by default (because the STL libraries is a separate port).
+ var compilerIncludePaths = input.cpp.compilerIncludePaths || [];
+ args = args.concat(compilerIncludePaths.map(function(path) {
+ return input.cpp.includeFlag + FileInfo.toWindowsSeparators(path);
+ }));
+ }
+
+ // Other includes.
+ args = args.concat(Cpp.collectIncludePaths(input).map(function(path) {
+ return input.cpp.includeFlag + FileInfo.toWindowsSeparators(path);
+ }));
+ args = args.concat(Cpp.collectSystemIncludePaths(input).map(function(path) {
+ return input.cpp.systemIncludeFlag + FileInfo.toWindowsSeparators(path);
+ }));
+
+ // Debug information flags.
+ if (input.cpp.debugInformation)
+ args.push("-d");
+
+ // Optimization flags.
+ switch (input.cpp.optimization) {
+ case "small":
+ args.push("-o+space");
+ break;
+ case "fast":
+ args.push("-o+speed");
+ break;
+ case "none":
+ args.push("-o+none");
+ break;
+ }
+
+ // Warning level flags.
+ switch (input.cpp.warningLevel) {
+ case "none":
+ args.push("-w");
+ break;
+ case "all":
+ args.push("-w-");
+ break;
+ }
+ if (input.cpp.treatWarningsAsErrors)
+ args.push("-wx");
+
+ if (tag === "cpp") {
+ args.push("-cpp");
+
+ // Exceptions flag.
+ if (input.cpp.enableExceptions)
+ args.push("-Ae");
+
+ // RTTI flag.
+ var enableRtti = input.cpp.enableRtti;
+ if (input.cpp.enableRtti)
+ args.push("-Ar");
+ }
+
+ // Listing files generation flag.
+ if (input.cpp.generateCompilerListingFiles) {
+ // We need to use the relative path here, because the DMC compiler does not handle
+ // a long file path for this option.
+ var listingPath = Cpp.relativePath(product.buildDirectory, outputs.lst[0].filePath);
+ args.push("-l" + FileInfo.toWindowsSeparators(listingPath));
+ }
+
+ // Misc flags.
+ args = args.concat(Cpp.collectMiscCompilerArguments(input, tag),
+ Cpp.collectMiscDriverArguments(product));
+ return args;
+}
+
+function assemblerFlags(project, product, input, outputs, explicitlyDependsOn) {
+ var args = ["-c"];
+
+ // Input.
+ args.push(FileInfo.toWindowsSeparators(input.filePath));
+ // Output.
+ args.push("-o" + FileInfo.toWindowsSeparators(outputs.obj[0].filePath));
+ // Preinclude headers.
+ args = args.concat(Cpp.collectPreincludePaths(input).map(function(path) {
+ return input.cpp.preincludeFlag + FileInfo.toWindowsSeparators(path);
+ }));
+
+ // Defines.
+ args = args.concat(Cpp.collectDefinesArguments(input));
+
+ // Other includes.
+ args = args.concat(Cpp.collectIncludePaths(input).map(function(path) {
+ return input.cpp.includeFlag + FileInfo.toWindowsSeparators(path);
+ }));
+ args = args.concat(Cpp.collectSystemIncludePaths(input).map(function(path) {
+ return input.cpp.systemIncludeFlag + FileInfo.toWindowsSeparators(path);
+ }));
+
+ // Misc flags.
+ args = args.concat(Cpp.collectMiscAssemblerArguments(input, "asm"));
+ return args;
+}
+
+function linkerFlags(project, product, inputs, outputs) {
+ var args = [];
+
+ var useCompilerDriver = useCompilerDriverLinker(product);
+ if (useCompilerDriver) {
+ // Input objects.
+ args = args.concat(Cpp.collectLinkerObjectPaths(inputs).map(function(path) {
+ return FileInfo.toWindowsSeparators(path);
+ }));
+
+ // Input resources.
+ args = args.concat(Cpp.collectResourceObjectPaths(inputs).map(function(path) {
+ return FileInfo.toWindowsSeparators(path);
+ }));
+
+ // Input libraries.
+ args = args.concat(Cpp.collectAbsoluteLibraryDependencyPaths(product).map(function(path) {
+ return FileInfo.toWindowsSeparators(path);
+ }));
+
+ // Output.
+ if (product.type.contains("application")) {
+ args.push("-o" + FileInfo.toWindowsSeparators(outputs.application[0].filePath));
+ args.push("-WA");
+ args.push("/SUBSYSTEM:" + (product.consoleApplication ? "CONSOLE" : "WINDOWS"));
+ } else if (product.type.contains("dynamiclibrary")) {
+ args.push("-o" + FileInfo.toWindowsSeparators(outputs.dynamiclibrary[0].filePath));
+ args.push("-WD");
+ }
+
+ if (product.cpp.debugInformation)
+ args.push("/DEBUG");
+
+ args.push("/NOLOGO", "/SILENT");
+ }
+
+ // Misc flags.
+ args = args.concat(Cpp.collectMiscEscapableLinkerArguments(product),
+ Cpp.collectMiscLinkerArguments(product),
+ Cpp.collectMiscDriverArguments(product));
+ return args;
+}
+
+function archiverFlags(project, product, inputs, outputs) {
+ var args = ["-c"];
+ // Output.
+ args.push(FileInfo.toWindowsSeparators(outputs.staticlibrary[0].filePath));
+ // Input objects.
+ args = args.concat(Cpp.collectLinkerObjectPaths(inputs).map(function(path) {
+ return FileInfo.toWindowsSeparators(path);
+ }));
+ return args;
+}
+
+function rccCompilerFlags(project, product, input, outputs) {
+ // Input.
+ var args = [FileInfo.toWindowsSeparators(input.filePath)];
+ // Output.
+ args.push("-o" + FileInfo.toWindowsSeparators(outputs.res[0].filePath));
+ // Bitness.
+ args.push("-32");
+
+ // Defines
+ args = args.concat(Cpp.collectDefinesArguments(input));
+
+ // Other includes.
+ args = args.concat(Cpp.collectIncludePaths(input).map(function(path) {
+ return input.cpp.includeFlag + FileInfo.toWindowsSeparators(path);
+ }));
+ args = args.concat(Cpp.collectSystemIncludePaths(input).map(function(path) {
+ return input.cpp.systemIncludeFlag + FileInfo.toWindowsSeparators(path);
+ }));
+ return args;
+}
+
+function buildLinkerMapFilePath(target, suffix) {
+ return FileInfo.joinPaths(FileInfo.path(target.filePath),
+ FileInfo.completeBaseName(target.fileName) + suffix);
+}
+
+// It is a workaround which removes the generated linker map file if it is disabled
+// by cpp.generateLinkerMapFile property. Reason is that the DMC compiler always
+// generates this file, and does not have an option to disable generation for a linker
+// map file. So, we can to remove a listing files only after the linking completes.
+function removeLinkerMapFile(project, product, inputs, outputs, input, output) {
+ var target = outputs.dynamiclibrary ? outputs.dynamiclibrary[0]
+ : outputs.application[0];
+ var cmd = new JavaScriptCommand();
+ cmd.mapFilePath = buildLinkerMapFilePath(target, ".map")
+ cmd.silent = true;
+ cmd.sourceCode = function() { File.remove(mapFilePath); };
+ return cmd;
+}
+
+// It is a workaround to rename the extension of the output linker map file to the
+// specified one, since the linker generates only files with the '.map' extension.
+function renameLinkerMapFile(project, product, inputs, outputs, input, output) {
+ var target = outputs.dynamiclibrary ? outputs.dynamiclibrary[0]
+ : outputs.application[0];
+ var cmd = new JavaScriptCommand();
+ cmd.newMapFilePath = buildLinkerMapFilePath(target, product.cpp.linkerMapSuffix);
+ cmd.oldMapFilePath = buildLinkerMapFilePath(target, ".map");
+ cmd.silent = true;
+ cmd.sourceCode = function() { File.move(oldMapFilePath, newMapFilePath); };
+ return cmd;
+}
+
+// It is a workaround to generate the import library file from the dynamic library.
+// Because the DMC compiler use the separate `implib.exe` tool for that.
+function createImportLib(project, product, inputs, outputs, input, output) {
+ var args = [
+ FileInfo.toWindowsSeparators(outputs.dynamiclibrary_import[0].filePath),
+ FileInfo.toWindowsSeparators(outputs.dynamiclibrary[0].filePath)
+ ];
+ var cmd = new Command(input.cpp.implibPath, args);
+ cmd.workingDirectory = product.buildDirectory;
+ cmd.silent = true;
+ return cmd;
+}
+
+function prepareCompiler(project, product, inputs, outputs, input, output, explicitlyDependsOn) {
+ var args = compilerFlags(project, product, input, outputs, explicitlyDependsOn);
+ var cmd = new Command(input.cpp.compilerPath, args);
+ cmd.workingDirectory = product.buildDirectory;
+ cmd.description = "compiling " + input.fileName;
+ cmd.highlight = "compiler";
+ return [cmd];
+}
+
+function prepareAssembler(project, product, inputs, outputs, input, output, explicitlyDependsOn) {
+ var args = assemblerFlags(project, product, input, outputs, explicitlyDependsOn);
+ var cmd = new Command(input.cpp.assemblerPath, args);
+ cmd.workingDirectory = product.buildDirectory;
+ cmd.description = "compiling " + input.fileName;
+ cmd.highlight = "compiler";
+ return [cmd];
+}
+
+function prepareLinker(project, product, inputs, outputs, input, output) {
+ var cmds = [];
+ var primaryOutput = outputs.dynamiclibrary ? outputs.dynamiclibrary[0]
+ : outputs.application[0];
+ var args = linkerFlags(project, product, inputs, outputs);
+ var linkerPath = effectiveLinkerPath(product);
+ var cmd = new Command(linkerPath, args);
+ cmd.workingDirectory = product.buildDirectory;
+ cmd.description = "linking " + primaryOutput.fileName;
+ cmd.highlight = "linker";
+ cmds.push(cmd);
+
+ if (outputs.dynamiclibrary
+ || (outputs.application && !product.cpp.generateLinkerMapFile)) {
+ if (outputs.dynamiclibrary)
+ cmds.push(createImportLib(project, product, inputs, outputs, input, output));
+ cmds.push(removeLinkerMapFile(project, product, inputs, outputs, input, output));
+ } else if (outputs.application
+ && product.cpp.generateLinkerMapFile
+ && (product.cpp.linkerMapSuffix !== ".map")) {
+ cmds.push(renameLinkerMapFile(project, product, inputs, outputs, input, output));
+ }
+ return cmds;
+}
+
+function prepareArchiver(project, product, inputs, outputs, input, output) {
+ var args = archiverFlags(project, product, inputs, outputs);
+ var cmd = new Command(product.cpp.archiverPath, args);
+ cmd.workingDirectory = product.buildDirectory;
+ cmd.description = "linking " + output.fileName;
+ cmd.highlight = "linker";
+ return [cmd];
+}
+
+function prepareRccCompiler(project, product, inputs, outputs, input, output) {
+ var args = rccCompilerFlags(project, product, input, outputs);
+ var cmd = new Command(input.cpp.rccCompilerPath, args);
+ cmd.workingDirectory = product.buildDirectory;
+ cmd.description = "compiling " + input.fileName;
+ cmd.highlight = "compiler";
+ return [cmd];
+}
diff --git a/share/qbs/modules/cpp/dmc.qbs b/share/qbs/modules/cpp/dmc.qbs
new file mode 100644
index 000000000..5369e84a7
--- /dev/null
+++ b/share/qbs/modules/cpp/dmc.qbs
@@ -0,0 +1,177 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 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.
+**
+****************************************************************************/
+
+import qbs.File
+import qbs.FileInfo
+import qbs.PathTools
+import qbs.Probes
+import qbs.Utilities
+import "dmc.js" as DMC
+import "cpp.js" as Cpp
+
+CppModule {
+ condition: qbs.hostOS.contains("windows") && qbs.toolchain && qbs.toolchain.contains("dmc")
+
+ Probes.BinaryProbe {
+ id: compilerPathProbe
+ condition: !toolchainInstallPath && !_skipAllChecks
+ names: ["cxcorm"]
+ }
+
+ Probes.DmcProbe {
+ id: dmcProbe
+ condition: !_skipAllChecks
+ compilerFilePath: compilerPath
+ enableDefinesByLanguage: enableCompilerDefinesByLanguage
+ }
+
+ qbs.architecture: dmcProbe.found ? dmcProbe.architecture : original
+ qbs.targetPlatform: dmcProbe.targetPlatform
+
+ compilerVersionMajor: dmcProbe.versionMajor
+ compilerVersionMinor: dmcProbe.versionMinor
+ compilerVersionPatch: dmcProbe.versionPatch
+ endianness: "little"
+
+ compilerDefinesByLanguage: dmcProbe.compilerDefinesByLanguage
+ compilerIncludePaths: dmcProbe.includePaths
+
+ toolchainInstallPath: compilerPathProbe.found ? compilerPathProbe.path : undefined
+
+ /* Work-around for QtCreator which expects these properties to exist. */
+ property string cCompilerName: compilerName
+ property string cxxCompilerName: compilerName
+
+ compilerName: "dmc.exe"
+ compilerPath: FileInfo.joinPaths(toolchainInstallPath, compilerName)
+
+ assemblerName: "dmc.exe"
+ assemblerPath: FileInfo.joinPaths(toolchainInstallPath, assemblerName)
+
+ linkerName: "link.exe"
+ linkerPath: FileInfo.joinPaths(toolchainInstallPath, linkerName)
+
+ property string archiverName: "lib.exe"
+ property string archiverPath: FileInfo.joinPaths(toolchainInstallPath, archiverName)
+ property string implibName: "implib.exe"
+ property string implibPath: FileInfo.joinPaths(toolchainInstallPath, implibName)
+ property string rccCompilerName: "rcc.exe"
+ property string rccCompilerPath: FileInfo.joinPaths(toolchainInstallPath, rccCompilerName)
+
+ runtimeLibrary: "dynamic"
+
+ staticLibrarySuffix: ".lib"
+ dynamicLibraryImportSuffix: ".lib"
+ dynamicLibrarySuffix: ".dll"
+ executableSuffix: ".exe"
+ objectSuffix: ".obj"
+ resourceSuffix: ".res"
+
+ imageFormat: "pe"
+
+ defineFlag: "-D"
+ includeFlag: "-I"
+ systemIncludeFlag: "-I"
+ preincludeFlag: "-HI"
+ libraryPathFlag: "-L/packcode"
+
+ knownArchitectures: ["x86"]
+
+ Rule {
+ id: assembler
+ inputs: ["asm"]
+ outputFileTags: DMC.depsOutputTags().concat(
+ Cpp.assemblerOutputTags(generateAssemblerListingFiles))
+ outputArtifacts: DMC.depsOutputArtifacts(input, product).concat(
+ Cpp.assemblerOutputArtifacts(input))
+ prepare: DMC.prepareAssembler.apply(DMC, arguments)
+ }
+
+ FileTagger {
+ patterns: ["*.s", "*.asm"]
+ fileTags: ["asm"]
+ }
+
+ Rule {
+ id: compiler
+ inputs: ["cpp", "c"]
+ auxiliaryInputs: ["hpp"]
+ outputFileTags: DMC.depsOutputTags().concat(
+ Cpp.compilerOutputTags(generateCompilerListingFiles))
+ outputArtifacts: DMC.depsOutputArtifacts(input, product).concat(
+ Cpp.compilerOutputArtifacts(input))
+ prepare: DMC.prepareCompiler.apply(DMC, arguments)
+ }
+
+
+ Rule {
+ id: rccCompiler
+ inputs: ["rc"]
+ auxiliaryInputs: ["hpp"]
+ outputFileTags: Cpp.resourceCompilerOutputTags()
+ outputArtifacts: Cpp.resourceCompilerOutputArtifacts(input)
+ prepare: DMC.prepareRccCompiler.apply(DMC, arguments)
+ }
+
+ FileTagger {
+ patterns: ["*.rc"]
+ fileTags: ["rc"]
+ }
+
+ Rule {
+ id: applicationLinker
+ multiplex: true
+ inputs: ["obj", "res", "linkerscript"]
+ inputsFromDependencies: ["staticlibrary", "dynamiclibrary_import"]
+ outputFileTags: Cpp.applicationLinkerOutputTags(generateLinkerMapFile)
+ outputArtifacts: Cpp.applicationLinkerOutputArtifacts(product)
+ prepare: DMC.prepareLinker.apply(DMC, arguments)
+ }
+
+ Rule {
+ id: dynamicLibraryLinker
+ multiplex: true
+ inputs: ["obj", "res"]
+ inputsFromDependencies: ["staticlibrary", "dynamiclibrary_import"]
+ outputFileTags: Cpp.dynamicLibraryLinkerOutputTags()
+ outputArtifacts: Cpp.dynamicLibraryLinkerOutputArtifacts(product)
+ prepare: DMC.prepareLinker.apply(DMC, arguments)
+ }
+
+ Rule {
+ id: staticLibraryLinker
+ multiplex: true
+ inputs: ["obj"]
+ inputsFromDependencies: ["staticlibrary", "dynamiclibrary_import"]
+ outputFileTags: Cpp.staticLibraryLinkerOutputTags()
+ outputArtifacts: Cpp.staticLibraryLinkerOutputArtifacts(product)
+ prepare: DMC.prepareArchiver.apply(DMC, arguments)
+ }
+}