aboutsummaryrefslogtreecommitdiffstats
path: root/src/app
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 /src/app
parent29b15e594f50314959ce9b63c4a39cc86e831475 (diff)
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>
Diffstat (limited to 'src/app')
-rw-r--r--src/app/qbs-setup-toolchains/dmcprobe.cpp240
1 files changed, 143 insertions, 97 deletions
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));
+ }
}