summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Shienkov <denis.shienkov@gmail.com>2022-02-10 18:32:34 +0300
committerDenis Shienkov <denis.shienkov@gmail.com>2022-02-17 12:34:25 +0000
commit2ddbafe29872d43245a7fba544dbdced21a09b7f (patch)
tree9fce25afa97ac4917e8ab1c37fc7c074c3fa7255
parent29b15e594f50314959ce9b63c4a39cc86e831475 (diff)
downloadqbs-2ddbafe29872d43245a7fba544dbdced21a09b7f.tar.gz
Add support for other platforms supported by Digital Mars
This patch adds support for the following target platforms: * DOS - both 32/16 bit. * Windows - 16 bit. Also, more specifically, the target is controlled by the `cpp.extenderName` property, which is the DOS extender to use. The Digital Mars support the following DOS extenders: * Rational 16 bit DOS Extender * ZPM 16 bit DOS Extender * DOSX 32 bit DOS Extender * Pharlap 32 bit DOS Extender which have the following names `dosr`, `dosz`, `dosx`, `dosp`. The user can set any of the desired values in the `cpp.extenderName` property (also this property can be empty that means no any extender is used). Right now the `qbs-setup-toolchain` utility creates all possible supported profiles with the required pre-configured properties: Profile 'dmc-8_57_0-windows-x86' created for 'C:/dm/bin/dmc.exe'. Profile 'dmc-8_57_0-windows-x86_16' created for 'C:/dm/bin/dmc.exe'. Profile 'dmc-8_57_0-dosx-x86' created for 'C:/dm/bin/dmc.exe'. Profile 'dmc-8_57_0-dosp-x86' created for 'C:/dm/bin/dmc.exe'. Profile 'dmc-8_57_0-dosr-x86_16' created for 'C:/dm/bin/dmc.exe'. Profile 'dmc-8_57_0-dosz-x86_16' created for 'C:/dm/bin/dmc.exe'. Profile 'dmc-8_57_0-dos-x86_16' created for 'C:/dm/bin/dmc.exe'. Compiling with DOS extenders requires additional external utilities and libraries (depending on the extender type). Some of them are no longer available at the moment, so the tests in CI are only done for the `dmc-windows-x86`, `dmc-windows-x86_16`, and `dmc-dos-x86_16` profiles. Change-Id: I221d2995900c63605c8552b825bf0c4d55171f5c Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
-rw-r--r--.github/workflows/main.yml14
-rw-r--r--doc/reference/items/probe/dmc-probe.qdoc31
-rw-r--r--scripts/install-dm.sh18
-rw-r--r--share/qbs/imports/qbs/ModUtils/utils.js4
-rw-r--r--share/qbs/imports/qbs/Probes/DmcProbe.qbs10
-rw-r--r--share/qbs/modules/cpp/dmc.js71
-rw-r--r--share/qbs/modules/cpp/dmc.qbs28
-rw-r--r--src/app/qbs-setup-toolchains/dmcprobe.cpp240
8 files changed, 287 insertions, 129 deletions
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 57f3c54e2..02e998dc9 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -835,8 +835,18 @@ jobs:
script: './scripts/test-baremetal.sh',
}
- {
- name: 'Run Windows tests (DigitalMars)',
- testProfile: 'dmc-8_42_0-x86',
+ name: 'Run Windows tests (DigitalMars DOS 16 bit)',
+ testProfile: 'dmc-8_57_0-dos-x86_16',
+ script: './scripts/test-baremetal.sh',
+ }
+ - {
+ name: 'Run Windows tests (DigitalMars Windows 32 bit)',
+ testProfile: 'dmc-8_57_0-windows-x86',
+ script: './scripts/test-baremetal.sh',
+ }
+ - {
+ name: 'Run Windows tests (DigitalMars Windows 16 bit)',
+ testProfile: 'dmc-8_57_0-windows-x86_16',
script: './scripts/test-baremetal.sh',
}
env:
diff --git a/doc/reference/items/probe/dmc-probe.qdoc b/doc/reference/items/probe/dmc-probe.qdoc
index 1cd8707bb..36d99cf93 100644
--- a/doc/reference/items/probe/dmc-probe.qdoc
+++ b/doc/reference/items/probe/dmc-probe.qdoc
@@ -54,17 +54,7 @@
Detected architecture of the target platform's processor.
- The only possible value is \c "x86".
-
- \nodefaultvalue
-*/
-
-/*!
- \qmlproperty string DmcProbe::endianness
-
- Detected endianness of the target platform's processor architecture.
-
- The possible value is \c "little".
+ The possible values are \c "x86" and \c "x86_16".
\nodefaultvalue
*/
@@ -74,7 +64,7 @@
Detected target platform.
- The possible value is \c "windows".
+ The possible values are \c "windows" and \c "dos".
\nodefaultvalue
*/
@@ -102,3 +92,20 @@
\nodefaultvalue
*/
+
+/*!
+ \qmlproperty stringList DmcProbe::includePaths
+
+ Detected compiler include paths.
+
+ \nodefaultvalue
+*/
+
+/*!
+ \qmlproperty var DmcProbe::compilerDefinesByLanguage
+
+ Detected set of compiler pre-defined macros depending
+ on the \c "C" or \c "C++" language.
+
+ \nodefaultvalue
+*/
diff --git a/scripts/install-dm.sh b/scripts/install-dm.sh
index 386329ecb..a13c8c8ea 100644
--- a/scripts/install-dm.sh
+++ b/scripts/install-dm.sh
@@ -95,9 +95,13 @@ DOWNLOAD_DIR=`mktemp -d 2>/dev/null || mktemp -d -t 'dm-tmp'`
DM_URL="http://ftp.digitalmars.com/Digital_Mars_C++/Patch/dm${VERSION//./}c.zip"
UTILS_URL="http://ftp.digitalmars.com/bup.zip"
+DOS_LIBS_URL="http://ftp.digitalmars.com/Digital_Mars_C++/Patch/dm850dos.zip"
+DOSX_LIBS_URL="http://ftp.digitalmars.com/Digital_Mars_C++/Patch/dm831x.zip"
DM_ZIP="${DOWNLOAD_DIR}/dm.zip"
UTILS_ZIP="${DOWNLOAD_DIR}/utils.zip"
+DOS_LIBS_ZIP="${DOWNLOAD_DIR}/doslibs.zip"
+DOSX_LIBS_ZIP="${DOWNLOAD_DIR}/dosxlibs.zip"
echo "Downloading compiler from ${DM_URL}..." >&2
curl --progress-bar -L -o ${DM_ZIP} ${DM_URL} >&2
@@ -105,13 +109,27 @@ curl --progress-bar -L -o ${DM_ZIP} ${DM_URL} >&2
echo "Downloading utils from ${UTILS_URL}..." >&2
curl --progress-bar -L -o ${UTILS_ZIP} ${UTILS_URL} >&2
+echo "Downloading DOS libs from ${DOS_LIBS_URL}..." >&2
+curl --progress-bar -L -o ${DOS_LIBS_ZIP} ${DOS_LIBS_URL} >&2
+
+echo "Downloading DOSX libs from ${DOSX_LIBS_URL}..." >&2
+curl --progress-bar -L -o ${DOSX_LIBS_ZIP} ${DOSX_LIBS_URL} >&2
+
echo "Unpacking compiler to ${INSTALL_DIR}..." >&2
7z x -y -o${INSTALL_DIR} ${DM_ZIP} >/dev/null 2>&1
echo "Unpacking utils to ${INSTALL_DIR}..." >&2
7z x -y -o${INSTALL_DIR} ${UTILS_ZIP} >/dev/null 2>&1
+echo "Unpacking DOS libs to ${INSTALL_DIR}..." >&2
+7z x -y -o${INSTALL_DIR} ${DOS_LIBS_ZIP} >/dev/null 2>&1
+
+echo "Unpacking DOSX libs to ${INSTALL_DIR}..." >&2
+7z x -y -o${INSTALL_DIR} ${DOSX_LIBS_ZIP} >/dev/null 2>&1
+
echo "${INSTALL_DIR}/dm/bin"
rm -f ${DM_ZIP}
rm -f ${UTILS_ZIP}
+rm -f ${DOS_LIBS_ZIP}
+rm -f ${DOSX_LIBS_ZIP}
diff --git a/share/qbs/imports/qbs/ModUtils/utils.js b/share/qbs/imports/qbs/ModUtils/utils.js
index 3fb4c170f..5e5cb63ea 100644
--- a/share/qbs/imports/qbs/ModUtils/utils.js
+++ b/share/qbs/imports/qbs/ModUtils/utils.js
@@ -613,9 +613,9 @@ function guessTargetPlatform(m) {
return "vxworks";
if (hasAnyOf(m, ["__APPLE__"]))
return "darwin";
- if (hasAnyOf(m, ["WIN32", "_WIN32", "__WIN32__", "__NT__", "__WINDOWS__"]))
+ if (hasAnyOf(m, ["WIN32", "_WIN32", "__WIN32__", "__NT__", "__WINDOWS__", "_WINDOWS"]))
return "windows";
- if (hasAnyOf(m, ["MSDOS", "__DOS__"]))
+ if (hasAnyOf(m, ["MSDOS", "__DOS__", "DOS386"]))
return "dos";
if (hasAnyOf(m, ["__OS2__"]))
return "os2";
diff --git a/share/qbs/imports/qbs/Probes/DmcProbe.qbs b/share/qbs/imports/qbs/Probes/DmcProbe.qbs
index 42672eee1..6a8723a3b 100644
--- a/share/qbs/imports/qbs/Probes/DmcProbe.qbs
+++ b/share/qbs/imports/qbs/Probes/DmcProbe.qbs
@@ -37,6 +37,10 @@ PathProbe {
property string compilerFilePath
property stringList enableDefinesByLanguage
+ property string _targetPlatform
+ property string _targetArchitecture
+ property string _targetExtender // Only for DOS 16/32 bit.
+
// Outputs
property string architecture
property string targetPlatform
@@ -62,7 +66,11 @@ PathProbe {
for (var i = 0; i < languages.length; ++i) {
var tag = languages[i];
compilerDefinesByLanguage[tag] = DMC.dumpMacros(
- compilerFilePath, tag);
+ compilerFilePath,
+ _targetPlatform,
+ _targetArchitecture,
+ _targetExtender,
+ tag);
var paths = DMC.dumpDefaultPaths(compilerFilePath, tag);
defaultPathsByLanguage[tag] = paths;
}
diff --git a/share/qbs/modules/cpp/dmc.js b/share/qbs/modules/cpp/dmc.js
index 23d03ba09..1137a0c0a 100644
--- a/share/qbs/modules/cpp/dmc.js
+++ b/share/qbs/modules/cpp/dmc.js
@@ -38,7 +38,47 @@ var TemporaryDir = require("qbs.TemporaryDir");
var TextFile = require("qbs.TextFile");
var Utilities = require("qbs.Utilities");
-function dumpMacros(compilerFilePath, tag) {
+function targetFlags(platform, architecture, extender, consoleApp, type) {
+ if (platform === "dos") {
+ if (architecture === "x86_16") {
+ if (extender === "dosz")
+ return ["-mz"];
+ else if (extender === "dosr")
+ return ["-mr"];
+ return ["-mc"];
+ } else if (architecture === "x86") {
+ if (extender === "dosx")
+ return ["-mx"];
+ else if (extender === "dosp")
+ return ["-mp"];
+ }
+ } else if (platform === "windows") {
+ var flags = [];
+ if (architecture === "x86_16") {
+ flags.push("-ml");
+ if (type.contains("application") && !consoleApp)
+ flags.push("-WA");
+ else if (type.contains("dynamiclibrary"))
+ flags.push("-WD");
+ } else if (architecture === "x86") {
+ flags.push("-mn");
+ if (type.contains("application"))
+ flags.push("-WA");
+ else if (type.contains("dynamiclibrary"))
+ flags.push("-WD");
+ }
+ return flags;
+ }
+ return [];
+}
+
+function languageFlags(tag) {
+ if (tag === "cpp")
+ return ["-cpp"];
+ return [];
+}
+
+function dumpMacros(compilerPath, platform, architecture, extender, 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>.
@@ -55,7 +95,8 @@ function dumpMacros(compilerFilePath, tag) {
"_MSDOS", "MSDOS",
// Prepare the OS/2 target macros.
"__OS2__",
- "WIN32", "_WIN32",
+ // Prepare the Windows target macros.
+ "WIN32", "_WIN32", "__NT__",
// Prepare extended the 32 and 16 bit DOS target macros.
"DOS386", "DOS16RM",
// Prepare the memory model macros.
@@ -96,9 +137,10 @@ function dumpMacros(compilerFilePath, tag) {
var process = new Process();
process.setWorkingDirectory(outputDirectory.path());
- var args = ["-c"].concat((tag === "cpp") ? ["-cpp"] : [],
- FileInfo.toWindowsSeparators(outputFilePath));
- process.exec(compilerFilePath, args, false);
+ var lang = languageFlags(tag);
+ var target = targetFlags(platform, architecture, extender, false, ["application"]);
+ var args = ["-c"].concat(lang, target, FileInfo.toWindowsSeparators(outputFilePath));
+ process.exec(compilerPath, args, false);
File.remove(outputFilePath);
var out = process.readStdOut();
return Cpp.extractMacros(out);
@@ -166,6 +208,12 @@ function depsOutputArtifacts(input, product) {
function compilerFlags(project, product, input, outputs, explicitlyDependsOn) {
var args = ["-c"];
+ var tag = ModUtils.fileTagForTargetLanguage(input.fileTags.concat(outputs.obj[0].fileTags));
+ args = args.concat(languageFlags(tag));
+ args = args.concat(targetFlags(product.qbs.targetPlatform, product.qbs.architecture,
+ product.cpp.extenderName, product.consoleApplication,
+ product.type));
+
// Input.
args.push(FileInfo.toWindowsSeparators(input.filePath));
// Output.
@@ -178,7 +226,6 @@ function compilerFlags(project, product, input, outputs, explicitlyDependsOn) {
// 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).
@@ -226,8 +273,6 @@ function compilerFlags(project, product, input, outputs, explicitlyDependsOn) {
args.push("-wx");
if (tag === "cpp") {
- args.push("-cpp");
-
// Exceptions flag.
if (input.cpp.enableExceptions)
args.push("-Ae");
@@ -285,6 +330,10 @@ function linkerFlags(project, product, inputs, outputs) {
var useCompilerDriver = useCompilerDriverLinker(product);
if (useCompilerDriver) {
+ args = args.concat(targetFlags(product.qbs.targetPlatform, product.qbs.architecture,
+ product.cpp.extenderName, product.consoleApplication,
+ product.type));
+
// Input objects.
args = args.concat(Cpp.collectLinkerObjectPaths(inputs).map(function(path) {
return FileInfo.toWindowsSeparators(path);
@@ -303,11 +352,11 @@ function linkerFlags(project, product, inputs, outputs) {
// 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"));
+ args.push("-L/" + (product.cpp.generateLinkerMapFile ? "MAP" : "NOMAP"));
+ if (product.qbs.targetPlatform === "windows" && product.qbs.architecture === "x86")
+ args.push("-L/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)
diff --git a/share/qbs/modules/cpp/dmc.qbs b/share/qbs/modules/cpp/dmc.qbs
index fe8ba25f1..f7f75169b 100644
--- a/share/qbs/modules/cpp/dmc.qbs
+++ b/share/qbs/modules/cpp/dmc.qbs
@@ -43,7 +43,7 @@ CppModule {
Probes.BinaryProbe {
id: compilerPathProbe
condition: !toolchainInstallPath && !_skipAllChecks
- names: ["cxcorm"]
+ names: ["dmc"]
}
Probes.DmcProbe {
@@ -51,10 +51,13 @@ CppModule {
condition: !_skipAllChecks
compilerFilePath: compilerPath
enableDefinesByLanguage: enableCompilerDefinesByLanguage
+ _targetPlatform: qbs.targetPlatform
+ _targetArchitecture: qbs.architecture
+ _targetExtender: extenderName
}
qbs.architecture: dmcProbe.found ? dmcProbe.architecture : original
- qbs.targetPlatform: dmcProbe.targetPlatform
+ qbs.targetPlatform: dmcProbe.found ? dmcProbe.targetPlatform : original
compilerVersionMajor: dmcProbe.versionMajor
compilerVersionMinor: dmcProbe.versionMinor
@@ -86,6 +89,18 @@ CppModule {
property string rccCompilerName: "rcc.exe"
property string rccCompilerPath: FileInfo.joinPaths(toolchainInstallPath, rccCompilerName)
+ property string extenderName
+ PropertyOptions {
+ name: "extenderName"
+ allowedValues: [undefined, "dosz", "dosr", "dosx", "dosp"]
+ description: "Specifies the DOS memory extender to compile with:\n"
+ + " - \"dosz\" is the ZPM 16 bit DOS Extender\n"
+ + " - \"dosr\" is the Rational 16 bit DOS Extender\n"
+ + " - \"dosx\" is the DOSX 32 bit DOS Extender\n"
+ + " - \"dosp\" is the Pharlap 32 bit DOS Extender\n"
+ ;
+ }
+
runtimeLibrary: "dynamic"
staticLibrarySuffix: ".lib"
@@ -93,7 +108,12 @@ CppModule {
executableSuffix: ".exe"
objectSuffix: ".obj"
- imageFormat: "pe"
+ imageFormat: {
+ if (qbs.targetPlatform === "dos")
+ return "mz";
+ else if (qbs.targetPlatform === "windows")
+ return "pe";
+ }
defineFlag: "-D"
includeFlag: "-I"
@@ -101,7 +121,7 @@ CppModule {
preincludeFlag: "-HI"
libraryPathFlag: "-L/packcode"
- knownArchitectures: ["x86"]
+ knownArchitectures: ["x86", "x86_16"]
Rule {
id: assembler
diff --git a/src/app/qbs-setup-toolchains/dmcprobe.cpp b/src/app/qbs-setup-toolchains/dmcprobe.cpp
index 6b74c5b9d..b858d2e90 100644
--- a/src/app/qbs-setup-toolchains/dmcprobe.cpp
+++ b/src/app/qbs-setup-toolchains/dmcprobe.cpp
@@ -54,124 +54,165 @@
#include <QtCore/qsettings.h>
#include <QtCore/qstandardpaths.h>
+#include <optional>
+
using namespace qbs;
using Internal::Tr;
using Internal::HostOsInfo;
+namespace {
+struct Target {
+ QString platform;
+ QString architecture;
+ QString extender;
+};
+}
+
static QStringList knownDmcCompilerNames()
{
return {QStringLiteral("dmc")};
}
-static QString guessDmcArchitecture(const QFileInfo &compiler)
+static QStringList dumpOutput(const QFileInfo &compiler, const QStringList &flags,
+ const QStringList &keys)
{
- const QStringList keys = {QStringLiteral("__I86__")};
- const auto macros = dumpMacros([&compiler, &keys]() {
- const QString filePath = QDir(QDir::tempPath())
- .absoluteFilePath(QLatin1String("dmc-dump.c"));
- QFile fakeIn(filePath);
- if (!fakeIn.open(QIODevice::Truncate | QIODevice::WriteOnly | QIODevice::Text)) {
- qbsWarning() << Tr::tr("Unable to open temporary file %1 for output: %2")
- .arg(fakeIn.fileName(), fakeIn.errorString());
- return QStringList{};
- }
- fakeIn.write("#define VALUE_TO_STRING(x) #x\n");
- fakeIn.write("#define VALUE(x) VALUE_TO_STRING(x)\n");
- fakeIn.write("#define VAR_NAME_VALUE(var) \"#define \" #var\" \"VALUE(var)\n");
- for (const QString &key : keys) {
- fakeIn.write("#if defined(" + key.toLatin1() + ")\n");
- fakeIn.write("#pragma message (VAR_NAME_VALUE(" + key.toLatin1() + "))\n");
- fakeIn.write("#endif\n");
- }
- fakeIn.close();
- QProcess p;
- p.start(compiler.absoluteFilePath(), {QStringLiteral("-e"), filePath});
- p.waitForFinished(3000);
- fakeIn.remove();
- const QStringList lines = QString::fromUtf8(p.readAllStandardOutput())
- .split(QRegularExpression(QLatin1String("\\r?\\n")));
- return lines;
- });
+ const QString filePath = QDir(QDir::tempPath()).absoluteFilePath(
+ QLatin1String("dmc-dump.c"));
+ QFile fakeIn(filePath);
+ if (!fakeIn.open(QIODevice::Truncate | QIODevice::WriteOnly | QIODevice::Text)) {
+ qbsWarning() << Tr::tr("Unable to open temporary file %1 for output: %2")
+ .arg(fakeIn.fileName(), fakeIn.errorString());
+ return {};
+ }
+ fakeIn.write("#define VALUE_TO_STRING(x) #x\n");
+ fakeIn.write("#define VALUE(x) VALUE_TO_STRING(x)\n");
+ fakeIn.write("#define VAR_NAME_VALUE(var) \"#define \" #var\" \"VALUE(var)\n");
+ for (const auto &key : keys) {
+ const auto content = key.toLatin1();
+ fakeIn.write("#if defined(" + content + ")\n");
+ fakeIn.write("#pragma message (VAR_NAME_VALUE(" + content + "))\n");
+ fakeIn.write("#endif\n");
+ }
+ fakeIn.close();
- for (const QString &key : keys) {
- if (macros.contains(key)) {
- bool ok = false;
- const auto value = macros.value(key).toInt(&ok);
- if (ok) {
- switch (value) {
- case 0: // 8088
- case 2: // 286
- case 3: // 386
- case 4: // 486
- break;
- case 5: // P5
- case 6: // P6
- return QLatin1String("x86");
- default:
- break;
- }
- }
- }
+ QStringList args = {QStringLiteral("-e")};
+ args.reserve(args.size() + int(flags.size()));
+ std::copy(flags.cbegin(), flags.cend(), std::back_inserter(args));
+ args.push_back(QDir::toNativeSeparators(filePath));
+
+ QProcess p;
+ p.start(compiler.absoluteFilePath(), std::move(args));
+ p.waitForFinished(3000);
+ fakeIn.remove();
+ static QRegularExpression re(QLatin1String("\\r?\\n"));
+ const QStringList lines = QString::fromUtf8(p.readAllStandardOutput()).split(re);
+ return lines;
+}
+
+static std::optional<Target> dumpDmcTarget(const QFileInfo &compiler, const QStringList &flags)
+{
+ const QStringList keys = {
+ QStringLiteral("DOS16RM"),
+ QStringLiteral("DOS386"),
+ QStringLiteral("MSDOS"),
+ QStringLiteral("__NT__"),
+ QStringLiteral("_WINDOWS"),
+ };
+ const auto macros = dumpMacros([&compiler, &flags, &keys]() {
+ return dumpOutput(compiler, flags, keys); });
+
+ if (macros.contains(QLatin1String("__NT__"))) {
+ return Target{QLatin1String("windows"), QLatin1String("x86"), QLatin1String("")};
+ } else if (macros.contains(QLatin1String("_WINDOWS"))) {
+ return Target{QLatin1String("windows"), QLatin1String("x86_16"), QLatin1String("")};
+ } else if (macros.contains(QLatin1String("DOS386"))) {
+ if (flags.contains(QLatin1String("-mx")))
+ return Target{QLatin1String("dos"), QLatin1String("x86"), QLatin1String("dosx")};
+ else if (flags.contains(QLatin1String("-mp")))
+ return Target{QLatin1String("dos"), QLatin1String("x86"), QLatin1String("dosp")};
+ } else if (macros.contains(QLatin1String("DOS16RM"))) {
+ if (flags.contains(QLatin1String("-mz")))
+ return Target{QLatin1String("dos"), QLatin1String("x86_16"), QLatin1String("dosz")};
+ else if (flags.contains(QLatin1String("-mr")))
+ return Target{QLatin1String("dos"), QLatin1String("x86_16"), QLatin1String("dosr")};
+ } else if (macros.contains(QLatin1String("MSDOS"))) {
+ return Target{QLatin1String("dos"), QLatin1String("x86_16"), QLatin1String("")};
}
- return QLatin1String("unknown");
+ return {};
}
-static Profile createDmcProfileHelper(const ToolchainInstallInfo &info,
- Settings *settings,
- QString profileName = QString())
+static std::vector<Profile> createDmcProfileHelper(const ToolchainInstallInfo &info,
+ Settings *settings,
+ QString profileName = QString())
{
const QFileInfo compiler = info.compilerPath;
- const QString architecture = guessDmcArchitecture(compiler);
+ std::vector<Profile> profiles;
+
+ const QVector<QStringList> probes = {
+ { QStringLiteral("-mn"), QStringLiteral("-WA") }, // Windows NT 32 bit.
+ { QStringLiteral("-ml"), QStringLiteral("-WA") }, // Windows 3.x 16 bit.
+ { QStringLiteral("-mx") }, // DOS with DOSX extender 32 bit.
+ { QStringLiteral("-mp") }, // DOS with Phar Lap extender 32 bit.
+ { QStringLiteral("-mr") }, // DOS with Rational DOS Extender 16 bit.
+ { QStringLiteral("-mz") }, // DOS with ZPM DOS Extender 16 bit.
+ { QStringLiteral("-mc") }, // DOS 16 bit.
+ };
+
+ for (const auto &flags : probes) {
+ const auto target = dumpDmcTarget(compiler, flags);
+ if (!target)
+ continue;
- // In case the profile is auto-detected.
- if (profileName.isEmpty()) {
- if (!info.compilerVersion.isValid()) {
- profileName = QStringLiteral("dmc-unknown-%1").arg(architecture);
+ QString fullProfilename;
+ QString platform = target->extender.isEmpty() ? target->platform : target->extender;
+ if (profileName.isEmpty()) {
+ // Create a full profile name in case we is in auto-detecting mode.
+ if (!info.compilerVersion.isValid()) {
+ fullProfilename = QStringLiteral("dmc-unknown-%1-%2")
+ .arg(platform, target->architecture);
+ } else {
+ const QString version = info.compilerVersion.toString(QLatin1Char('_'),
+ QLatin1Char('_'));
+ fullProfilename = QStringLiteral("dmc-%1-%2-%3")
+ .arg(version, platform, target->architecture);
+ }
} else {
- const QString version = info.compilerVersion.toString(QLatin1Char('_'),
- QLatin1Char('_'));
- profileName = QStringLiteral("dmc-%1-%2").arg(
- version, architecture);
+ // Append the detected actual architecture name to the proposed profile name.
+ fullProfilename = QStringLiteral("%1-%2-%3")
+ .arg(profileName, platform, target->architecture);
}
- }
- Profile profile(profileName, settings);
- profile.setValue(QLatin1String("cpp.toolchainInstallPath"), compiler.absolutePath());
- profile.setValue(QLatin1String("qbs.toolchainType"), QLatin1String("dmc"));
- if (!architecture.isEmpty())
- profile.setValue(QLatin1String("qbs.architecture"), architecture);
+ Profile profile(fullProfilename, settings);
+ profile.setValue(QStringLiteral("cpp.toolchainInstallPath"), compiler.absolutePath());
+ profile.setValue(QStringLiteral("qbs.toolchainType"), QStringLiteral("dmc"));
+ profile.setValue(QStringLiteral("qbs.architecture"), target->architecture);
+ profile.setValue(QStringLiteral("qbs.targetPlatform"), target->platform);
+ if (!target->extender.isEmpty())
+ profile.setValue(QStringLiteral("cpp.extenderName"), target->extender);
+
+ qbsInfo() << Tr::tr("Profile '%1' created for '%2'.")
+ .arg(profile.name(), compiler.absoluteFilePath());
+
+ profiles.push_back(std::move(profile));
+ }
- qbsInfo() << Tr::tr("Profile '%1' created for '%2'.").arg(
- profile.name(), compiler.absoluteFilePath());
- return profile;
+ return profiles;
}
-static Version dumpDmcCompilerVersion(const QFileInfo &compiler)
+static Version dumpDmcVersion(const QFileInfo &compiler)
{
- QProcess p;
- QStringList args;
- p.start(compiler.absoluteFilePath(), args);
- p.waitForFinished(3000);
- const auto es = p.exitStatus();
- if (es != QProcess::NormalExit) {
- const QByteArray out = p.readAll();
- qbsWarning() << Tr::tr("Compiler dumping failed:\n%1")
- .arg(QString::fromUtf8(out));
- return Version{};
+ const QStringList keys = {QStringLiteral("__DMC__")};
+ const auto macros = dumpMacros([&compiler, keys]() {
+ return dumpOutput(compiler, {}, keys); });
+ for (const auto &macro : macros) {
+ if (!macro.startsWith(QLatin1String("0x")))
+ continue;
+ const int verCode = macro.midRef(2).toInt();
+ return Version{(verCode / 100), (verCode % 100), 0};
}
-
- const QByteArray output = p.readAllStandardOutput();
- const QRegularExpression re(QLatin1String(
- "^Digital Mars Compiler Version (\\d+)\\.?(\\d+)\\.?(\\*|\\d+)?"));
- const QRegularExpressionMatch match = re.match(QString::fromLatin1(output));
- if (!match.hasMatch())
- return Version{};
-
- const auto major = match.captured(1).toInt();
- const auto minor = match.captured(2).toInt();
- const auto patch = match.captured(3).toInt();
- return Version{major, minor, patch};
+ qbsWarning() << Tr::tr("No __DMC__ token was found in the compiler dump");
+ return Version{};
}
static std::vector<ToolchainInstallInfo> installedDmcsFromPath()
@@ -184,7 +225,7 @@ static std::vector<ToolchainInstallInfo> installedDmcsFromPath()
HostOsInfo::appendExecutableSuffix(compilerName)));
if (!dmcPath.exists())
continue;
- const Version version = dumpDmcCompilerVersion(dmcPath);
+ const Version version = dumpDmcVersion(dmcPath);
infos.push_back({dmcPath, version});
}
std::sort(infos.begin(), infos.end());
@@ -211,9 +252,14 @@ void dmcProbe(Settings *settings, std::vector<Profile> &profiles)
qbsInfo() << Tr::tr("Trying to detect DMC toolchains...");
const std::vector<ToolchainInstallInfo> allInfos = installedDmcsFromPath();
- qbs::Internal::transform(allInfos, profiles, [settings](const auto &info) {
- return createDmcProfileHelper(info, settings); });
-
- if (allInfos.empty())
+ if (allInfos.empty()) {
qbsInfo() << Tr::tr("No DMC toolchains found.");
+ return;
+ }
+
+ for (const ToolchainInstallInfo &info : allInfos) {
+ const auto newProfiles = createDmcProfileHelper(info, settings);
+ profiles.reserve(profiles.size() + int(newProfiles.size()));
+ std::copy(newProfiles.cbegin(), newProfiles.cend(), std::back_inserter(profiles));
+ }
}