Commit 0cdd2672 authored by Tobias Hunger's avatar Tobias Hunger Committed by Tim Jenssen

QtSupport: Use binary string from Qt's libraryLoader to refine ABI

Use binary string from Qt's library loader class to refine ABI if that
is not complete yet. This is necessary to reliably find the compiler
used in static Qt builds on windows (using MSVC compilers). Before we
were able to rely on the mkspec to pick a working compiler, that does no
longer work with Qt 5.8.

Task-number: QTCREATORBUG-17534
Change-Id: I50c428cbaa986a26ba165cff499f9e0be3937ea2
Reviewed-by: Tim Jenssen's avatarTim Jenssen <tim.jenssen@qt.io>
parent 1c5e771b
......@@ -47,7 +47,6 @@
#include <utils/runextensions.h>
#include <utils/synchronousprocess.h>
#include <utils/winutils.h>
#include <utils/algorithm.h>
#include <QDir>
#include <QUrl>
......@@ -57,6 +56,8 @@
#include <QProcess>
#include <QRegularExpression>
#include <algorithm>
using namespace Core;
using namespace QtSupport;
using namespace QtSupport::Internal;
......@@ -1734,12 +1735,147 @@ FileNameList BaseQtVersion::qtCorePaths(const QHash<QString,QString> &versionInf
return dynamicLibs;
}
static QByteArray scanQtBinaryForBuildString(const FileName &library)
{
QFile lib(library.toString());
QByteArray buildString;
if (lib.open(QIODevice::ReadOnly)) {
const QByteArray startNeedle = "Qt ";
const QByteArray buildNeedle = " build; by ";
const size_t oneMiB = 1024 * 1024;
const size_t keepSpace = 4096;
const size_t bufferSize = oneMiB + keepSpace;
QByteArray buffer(bufferSize, '\0');
char *const readStart = buffer.data() + keepSpace;
auto readStartIt = buffer.begin() + keepSpace;
const auto copyStartIt = readStartIt + (oneMiB - keepSpace);
while (!lib.atEnd()) {
const int read = lib.read(readStart, static_cast<int>(oneMiB));
const auto readEndIt = readStart + read;
auto currentIt = readStartIt;
forever {
const auto qtFoundIt = std::search(currentIt, readEndIt,
startNeedle.begin(), startNeedle.end());
if (qtFoundIt == readEndIt)
break;
currentIt = qtFoundIt + 1;
// Found "Qt ", now find the next '\0'.
const auto nullFoundIt = std::find(qtFoundIt, readEndIt, '\0');
if (nullFoundIt == readEndIt)
break;
// String much too long?
const size_t len = std::distance(qtFoundIt, nullFoundIt);
if (len > keepSpace)
continue;
// Does it contain " build; by "?
const auto buildByFoundIt = std::search(qtFoundIt, nullFoundIt,
buildNeedle.begin(), buildNeedle.end());
if (buildByFoundIt == nullFoundIt)
continue;
buildString = QByteArray(qtFoundIt, len);
break;
}
if (!buildString.isEmpty() || readEndIt != buffer.constEnd())
break;
std::move(copyStartIt, readEndIt, buffer.begin()); // Copy last section to front.
}
}
return buildString;
}
static Abi refineAbiFromBuildString(const QByteArray &buildString, const Abi &probableAbi)
{
if (buildString.isEmpty()
|| buildString.count() > 4096)
return Abi();
const QRegularExpression buildStringMatcher("^Qt "
"([\\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
"(shared|static) (?:\\(dynamic\\) )?"
"(debug|release)"
" build; by "
"(.*)" // 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);
Abi::Architecture arch = probableAbi.architecture();
Abi::OS os = probableAbi.os();
Abi::OSFlavor flavor = probableAbi.osFlavor();
Abi::BinaryFormat format = probableAbi.binaryFormat();
unsigned char wordWidth = probableAbi.wordWidth();
if (compiler.startsWith("GCC ") && os == Abi::WindowsOS) {
flavor = Abi::WindowsMSysFlavor;
} else if (compiler.startsWith("MSVC 2005") && os == Abi::WindowsOS) {
flavor = Abi::WindowsMsvc2005Flavor;
} else if (compiler.startsWith("MSVC 2008") && os == Abi::WindowsOS) {
flavor = Abi::WindowsMsvc2008Flavor;
} else if (compiler.startsWith("MSVC 2010") && os == Abi::WindowsOS) {
flavor = Abi::WindowsMsvc2010Flavor;
} else if (compiler.startsWith("MSVC 2012") && os == Abi::WindowsOS) {
flavor = Abi::WindowsMsvc2012Flavor;
} else if (compiler.startsWith("MSVC 2015") && os == Abi::WindowsOS) {
flavor = Abi::WindowsMsvc2015Flavor;
} else if (compiler.startsWith("MSVC 2017") && os == Abi::WindowsOS) {
flavor = Abi::WindowsMsvc2017Flavor;
}
return Abi(arch, os, flavor, format, wordWidth);
}
static Abi scanQtBinaryForBuildStringAndRefineAbi(const FileName &library,
const Abi &probableAbi)
{
static QHash<Utils::FileName, Abi> results;
if (!results.contains(library)) {
const QByteArray buildString = scanQtBinaryForBuildString(library);
results.insert(library, refineAbiFromBuildString(buildString, probableAbi));
}
return results.value(library);
}
QList<Abi> BaseQtVersion::qtAbisFromLibrary(const FileNameList &coreLibraries)
{
QList<Abi> res;
foreach (const FileName &library, coreLibraries)
foreach (const Abi &abi, Abi::abisOfBinary(library))
if (!res.contains(abi))
res.append(abi);
foreach (const FileName &library, coreLibraries) {
for (Abi abi : Abi::abisOfBinary(library)) {
Abi tmp = abi;
if (abi.osFlavor() == Abi::UnknownFlavor)
tmp = scanQtBinaryForBuildStringAndRefineAbi(library, abi);
if (!res.contains(tmp))
res.append(tmp);
}
}
return res;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment