aboutsummaryrefslogtreecommitdiffstats
path: root/src/app/qbs-setup-toolchains/sdccprobe.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/app/qbs-setup-toolchains/sdccprobe.cpp')
-rw-r--r--src/app/qbs-setup-toolchains/sdccprobe.cpp161
1 files changed, 127 insertions, 34 deletions
diff --git a/src/app/qbs-setup-toolchains/sdccprobe.cpp b/src/app/qbs-setup-toolchains/sdccprobe.cpp
index 751e872ee..e916a405b 100644
--- a/src/app/qbs-setup-toolchains/sdccprobe.cpp
+++ b/src/app/qbs-setup-toolchains/sdccprobe.cpp
@@ -47,9 +47,9 @@
#include <tools/hostosinfo.h>
#include <tools/profile.h>
-#include <QtCore/qfileinfo.h>
-#include <QtCore/qlist.h>
+#include <QtCore/qprocess.h>
#include <QtCore/qsettings.h>
+#include <QtCore/qtemporaryfile.h>
using namespace qbs;
using Internal::Tr;
@@ -60,37 +60,119 @@ static QStringList knownSdccCompilerNames()
return {QStringLiteral("sdcc")};
}
-static QString guessSdccArchitecture(const QFileInfo &compiler)
+static QByteArray dumpSdccMacros(const QFileInfo &compiler,
+ const QString &targetFlag = QString())
{
- const auto baseName = compiler.baseName();
- if (baseName == QLatin1String("sdcc"))
- return QStringLiteral("mcs51");
- return {};
+ QTemporaryFile fakeIn(QStringLiteral("XXXXXX.c"));
+ if (!fakeIn.open()) {
+ qbsWarning() << Tr::tr("Unable to open temporary file %1 for output: %2")
+ .arg(fakeIn.fileName(), fakeIn.errorString());
+ return {};
+ }
+ fakeIn.close();
+
+ const QStringList args = {QStringLiteral("-dM"),
+ QStringLiteral("-E"),
+ targetFlag,
+ fakeIn.fileName()};
+ QProcess p;
+ 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 {};
+ }
+
+ return p.readAllStandardOutput();
+}
+
+static QString dumpSdccArchitecture(const QFileInfo &compiler,
+ const QString &arch)
+{
+ const auto targetFlag = QStringLiteral("-m%1").arg(arch);
+ const auto token = QStringLiteral("__SDCC_%1").arg(arch);
+ const auto macros = dumpSdccMacros(compiler, targetFlag);
+ return macros.contains(token.toLatin1()) ? arch : QString();
}
-static Profile createSdccProfileHelper(const QFileInfo &compiler, Settings *settings,
- QString profileName = QString())
+static std::vector<Profile> createSdccProfileHelper(
+ const ToolchainInstallInfo &info,
+ Settings *settings,
+ const QString &profileName = QString())
{
- const QString architecture = guessSdccArchitecture(compiler);
+ const QFileInfo compiler = info.compilerPath;
+
+ std::vector<Profile> profiles;
+
+ const char *knownArchs[] = {"mcs51", "stm8"};
+ for (const auto &knownArch : knownArchs) {
+ const auto actualArch = dumpSdccArchitecture(
+ compiler, QString::fromLatin1(knownArch));
+ // Don't create a profile in case the compiler does
+ // not support the proposed architecture.
+ if (actualArch != QString::fromLatin1(knownArch))
+ continue;
- // In case the profile is auto-detected.
- if (profileName.isEmpty())
- profileName = QLatin1String("sdcc-") + architecture;
+ QString fullProfileName = profileName;
+ if (fullProfileName.isEmpty()) {
+ // Create a full profile name in case we is
+ // in auto-detecting mode.
+ if (!info.compilerVersion.isValid()) {
+ fullProfileName = QStringLiteral("sdcc-unknown-%1")
+ .arg(actualArch);
+ } else {
+ const QString version = info.compilerVersion.toString(
+ QLatin1Char('_'), QLatin1Char('_'));
+ fullProfileName = QStringLiteral("sdcc-%1-%2").arg(
+ version, actualArch);
+ }
+ } else {
+ // Append the detected actual architecture name
+ // to the proposed profile name.
+ fullProfileName = QStringLiteral("%1-%2").arg(
+ fullProfileName, actualArch);
+ }
+
+ Profile profile(fullProfileName, settings);
+ profile.setValue(QStringLiteral("cpp.toolchainInstallPath"),
+ compiler.absolutePath());
+ profile.setValue(QStringLiteral("qbs.toolchainType"),
+ QStringLiteral("sdcc"));
+ if (!actualArch.isEmpty())
+ profile.setValue(QStringLiteral("qbs.architecture"), actualArch);
+
+ qbsInfo() << Tr::tr("Profile '%1' created for '%2'.").arg(
+ profile.name(), compiler.absoluteFilePath());
+ }
- Profile profile(profileName, settings);
- profile.setValue(QStringLiteral("cpp.toolchainInstallPath"), compiler.absolutePath());
- profile.setValue(QStringLiteral("qbs.toolchainType"), QStringLiteral("sdcc"));
- if (!architecture.isEmpty())
- profile.setValue(QStringLiteral("qbs.architecture"), architecture);
+ return profiles;
+}
+
+static Version dumpSdccCompilerVersion(const QFileInfo &compiler)
+{
+ const QByteArray dump = dumpSdccMacros(compiler);
+ if (dump.isEmpty())
+ return Version{};
+
+ const int major = extractVersion(dump, "__SDCC_VERSION_MAJOR ");
+ const int minor = extractVersion(dump, "__SDCC_VERSION_MINOR ");
+ const int patch = extractVersion(dump, "__SDCC_VERSION_PATCH ");
+ if (major < 0 || minor < 0 || patch < 0) {
+ qbsWarning() << Tr::tr("No '__SDCC_VERSION_xxx' token was found "
+ "in the compiler dump:\n%1")
+ .arg(QString::fromUtf8(dump));
+ return Version{};
+ }
- qbsInfo() << Tr::tr("Profile '%1' created for '%2'.").arg(
- profile.name(), compiler.absoluteFilePath());
- return profile;
+ return Version{major, minor, patch};
}
-static std::vector<SdccInstallInfo> installedSdccsFromPath()
+static std::vector<ToolchainInstallInfo> installedSdccsFromPath()
{
- std::vector<SdccInstallInfo> infos;
+ std::vector<ToolchainInstallInfo> infos;
const auto compilerNames = knownSdccCompilerNames();
for (const QString &compilerName : compilerNames) {
const QFileInfo sdccPath(
@@ -98,14 +180,16 @@ static std::vector<SdccInstallInfo> installedSdccsFromPath()
HostOsInfo::appendExecutableSuffix(compilerName)));
if (!sdccPath.exists())
continue;
- infos.push_back({sdccPath.absoluteFilePath(), {}});
+ const Version version = dumpSdccCompilerVersion(sdccPath);
+ infos.push_back({sdccPath, version});
}
+ std::sort(infos.begin(), infos.end());
return infos;
}
-static std::vector<SdccInstallInfo> installedSdccsFromRegistry()
+static std::vector<ToolchainInstallInfo> installedSdccsFromRegistry()
{
- std::vector<SdccInstallInfo> infos;
+ std::vector<ToolchainInstallInfo> infos;
if (HostOsInfo::isWindowsHost()) {
@@ -126,11 +210,12 @@ static std::vector<SdccInstallInfo> installedSdccsFromRegistry()
registry.value(QStringLiteral("VersionMajor")).toString(),
registry.value(QStringLiteral("VersionMinor")).toString(),
registry.value(QStringLiteral("VersionRevision")).toString());
- infos.push_back({sdccPath.absoluteFilePath(), version});
+ infos.push_back({sdccPath, Version::fromString(version)});
}
}
}
+ std::sort(infos.begin(), infos.end());
return infos;
}
@@ -145,20 +230,28 @@ bool isSdccCompiler(const QString &compilerName)
void createSdccProfile(const QFileInfo &compiler, Settings *settings,
QString profileName)
{
- createSdccProfileHelper(compiler, settings, profileName);
+ const ToolchainInstallInfo info = {compiler, Version{}};
+ createSdccProfileHelper(info, settings, profileName);
}
void sdccProbe(Settings *settings, QList<Profile> &profiles)
{
qbsInfo() << Tr::tr("Trying to detect SDCC toolchains...");
- std::vector<SdccInstallInfo> allInfos = installedSdccsFromRegistry();
- const std::vector<SdccInstallInfo> pathInfos = installedSdccsFromPath();
- allInfos.insert(std::end(allInfos), std::begin(pathInfos), std::end(pathInfos));
+ // Make sure that a returned infos are sorted before using the std::set_union!
+ const std::vector<ToolchainInstallInfo> regInfos = installedSdccsFromRegistry();
+ const std::vector<ToolchainInstallInfo> pathInfos = installedSdccsFromPath();
+ std::vector<ToolchainInstallInfo> allInfos;
+ allInfos.reserve(regInfos.size() + pathInfos.size());
+ std::set_union(regInfos.cbegin(), regInfos.cend(),
+ pathInfos.cbegin(), pathInfos.cend(),
+ std::back_inserter(allInfos));
- for (const SdccInstallInfo &info : allInfos) {
- const auto profile = createSdccProfileHelper(info.compilerPath, settings);
- profiles.push_back(profile);
+ for (const ToolchainInstallInfo &info : allInfos) {
+ const auto newProfiles = createSdccProfileHelper(info, settings);
+ profiles.reserve(profiles.size() + int(newProfiles.size()));
+ std::copy(newProfiles.cbegin(), newProfiles.cend(),
+ std::back_inserter(profiles));
}
if (allInfos.empty())