From 68e5691047f3b89b1c88b7a9e7e45309b10c6bd1 Mon Sep 17 00:00:00 2001 From: Tobias Hunger Date: Fri, 13 Jan 2017 10:44:52 +0100 Subject: [PATCH] BaseQtVersion: Fix Qt build string parsing This fixes Qt build string parsing based on feedback from Thiago. Also adds unit test for the code that parses the build string so that we can be more sure that it actually works as expected. Change-Id: I23cff7125be4c7c87d5eba4b1db7cb47c2479b66 Reviewed-by: Thiago Macieira Reviewed-by: Tim Jenssen --- src/plugins/qtsupport/baseqtversion.cpp | 129 ++++++++++++++++++++---- src/plugins/qtsupport/qtsupportplugin.h | 4 + 2 files changed, 112 insertions(+), 21 deletions(-) diff --git a/src/plugins/qtsupport/baseqtversion.cpp b/src/plugins/qtsupport/baseqtversion.cpp index 1c1021a08f9..662ad029754 100644 --- a/src/plugins/qtsupport/baseqtversion.cpp +++ b/src/plugins/qtsupport/baseqtversion.cpp @@ -1746,7 +1746,7 @@ static QByteArray scanQtBinaryForBuildString(const FileName &library) const size_t oneMiB = 1024 * 1024; const size_t keepSpace = 4096; const size_t bufferSize = oneMiB + keepSpace; - QByteArray buffer(bufferSize, '\0'); + QByteArray buffer(bufferSize, Qt::Uninitialized); char *const readStart = buffer.data() + keepSpace; auto readStartIt = buffer.begin() + keepSpace; @@ -1794,39 +1794,72 @@ static QByteArray scanQtBinaryForBuildString(const FileName &library) return buildString; } -static Abi refineAbiFromBuildString(const QByteArray &buildString, const Abi &probableAbi) +static QStringList extractFieldsFromBuildString(const QByteArray &buildString) { if (buildString.isEmpty() || buildString.count() > 4096) - return Abi(); + return QStringList(); const QRegularExpression buildStringMatcher("^Qt " - "([\\d\\.a-zA-Z]*) " // Qt version + "([\\d\\.a-zA-Z]*) " // Qt version "\\(" - "([a-z\\d_]*)-" // CPU - "(big|little)_endian-" - "([a-z]+(?:32|64))" // pointer information - "(?:-(qreal|))?" // extra information like -qreal - "(?:-([^-]+))? " // ABI information + "([\\w_-]+) " // Abi information "(shared|static) (?:\\(dynamic\\) )?" "(debug|release)" " build; by " - "(.*)" // compiler with extra info + "(.*)" // compiler with extra info "\\)$"); QTC_ASSERT(buildStringMatcher.isValid(), qWarning() << buildStringMatcher.errorString()); - const QRegularExpressionMatch match = buildStringMatcher.match(QString::fromUtf8(buildString)); - QTC_ASSERT(match.hasMatch(), return Abi()); - // const QString qtVersion = match.captured(1); - // const QString cpu = match.captured(2); - // const bool littleEndian = (match.captured(3) == "little"); - // const QString pointer = match.captured(4); - // const QString extra = match.captured(5); - // const QString abiString = match.captured(6); - // const QString linkage = match.captured(7); - // const QString buildType = match.captured(8); - const QString compiler = match.captured(9); + const QRegularExpressionMatch match = buildStringMatcher.match(QString::fromUtf8(buildString)); + if (!match.hasMatch()) + return QStringList(); + + QStringList result; + result.append(match.captured(1)); // qtVersion + + // Abi info string: + QStringList abiInfo = match.captured(2).split('-', QString::SkipEmptyParts); + + result.append(abiInfo.takeFirst()); // cpu + + const QString endian = abiInfo.takeFirst(); + QTC_ASSERT(endian.endsWith("_endian"), return QStringList()); + result.append(endian.left(endian.count() - 7)); // without the "_endian" + + result.append(abiInfo.takeFirst()); // pointer + + if (abiInfo.isEmpty()) { + // no extra info whatsoever: + result.append(""); // qreal is unset + result.append(""); // extra info is unset + } else { + const QString next = abiInfo.at(0); + if (next.startsWith("qreal_")) { + abiInfo.takeFirst(); + result.append(next.mid(6)); // qreal: without the "qreal_" part; + } else { + result.append(""); // qreal is unset! + } + + result.append(abiInfo.join('-')); // extra abi strings + } + + result.append(match.captured(3)); // linkage + result.append(match.captured(4)); // buildType + result.append(match.captured(5)); // compiler + + return result; +} + +static Abi refineAbiFromBuildString(const QByteArray &buildString, const Abi &probableAbi) +{ + QStringList buildStringData = extractFieldsFromBuildString(buildString); + if (buildStringData.count() != 9) + return probableAbi; + + const QString compiler = buildStringData.at(8); Abi::Architecture arch = probableAbi.architecture(); Abi::OS os = probableAbi.os(); @@ -1879,3 +1912,57 @@ QList BaseQtVersion::qtAbisFromLibrary(const FileNameList &coreLibraries) } return res; } + +#if defined(WITH_TESTS) + +#include + +#include "qtsupportplugin.h" + +void QtSupportPlugin::testQtBuildStringParsing_data() +{ + QTest::addColumn("buildString"); + QTest::addColumn("expected"); + + QTest::newRow("invalid build string") + << QByteArray("Qt with invalid buildstring") << QString(); + QTest::newRow("empty build string") + << QByteArray("") << QString(); + QTest::newRow("huge build string") + << QByteArray(8192, 'x') << QString(); + + QTest::newRow("valid build string") + << QByteArray("Qt 5.7.1 (x86_64-little_endian-lp64 shared (dynamic) release build; by GCC 6.2.1 20160830)") + << "5.7.1;x86_64;little;lp64;;;shared;release;GCC 6.2.1 20160830"; + + QTest::newRow("with qreal") + << QByteArray("Qt 5.7.1 (x86_64-little_endian-lp64-qreal___fp16 shared (dynamic) release build; by GCC 6.2.1 20160830)") + << "5.7.1;x86_64;little;lp64;__fp16;;shared;release;GCC 6.2.1 20160830"; + QTest::newRow("with qreal and abi") + << QByteArray("Qt 5.7.1 (x86_64-little_endian-lp64-qreal___fp16-eabi shared (dynamic) release build; by GCC 6.2.1 20160830)") + << "5.7.1;x86_64;little;lp64;__fp16;eabi;shared;release;GCC 6.2.1 20160830"; + QTest::newRow("with qreal, eabi and softfloat") + << QByteArray("Qt 5.7.1 (x86_64-little_endian-lp64-qreal___fp16-eabi-softfloat shared (dynamic) release build; by GCC 6.2.1 20160830)") + << "5.7.1;x86_64;little;lp64;__fp16;eabi-softfloat;shared;release;GCC 6.2.1 20160830"; + QTest::newRow("with eabi") + << QByteArray("Qt 5.7.1 (x86_64-little_endian-lp64-eabi shared (dynamic) release build; by GCC 6.2.1 20160830)") + << "5.7.1;x86_64;little;lp64;;eabi;shared;release;GCC 6.2.1 20160830"; + QTest::newRow("with eabi and softfloat") + << QByteArray("Qt 5.7.1 (x86_64-little_endian-lp64-eabi-softfloat shared (dynamic) release build; by GCC 6.2.1 20160830)") + << "5.7.1;x86_64;little;lp64;;eabi-softfloat;shared;release;GCC 6.2.1 20160830"; +} + +void QtSupportPlugin::testQtBuildStringParsing() +{ + QFETCH(QByteArray, buildString); + QFETCH(QString, expected); + + QStringList expectedList; + if (!expected.isEmpty()) + expectedList = expected.split(';'); + + QStringList actual = extractFieldsFromBuildString(buildString); + QCOMPARE(expectedList, actual); +} + +#endif // WITH_TESTS diff --git a/src/plugins/qtsupport/qtsupportplugin.h b/src/plugins/qtsupport/qtsupportplugin.h index fe0585c50fc..1756b2a1c45 100644 --- a/src/plugins/qtsupport/qtsupportplugin.h +++ b/src/plugins/qtsupport/qtsupportplugin.h @@ -53,6 +53,10 @@ private slots: void testQtProjectImporter_oneProject_data(); void testQtProjectImporter_oneProject(); + + void testQtBuildStringParsing_data(); + void testQtBuildStringParsing(); + #if 0 void testQtProjectImporter_oneProjectExistingKit(); void testQtProjectImporter_oneProjectNewKitExistingQt();