diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/app/qbs-setup-toolchains/dmcprobe.cpp | 240 |
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 ¯o : 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)); + } } |