forked from qt-creator/qt-creator
Handle static Qt libraries on mac
This commit is contained in:
@@ -41,6 +41,124 @@
|
|||||||
|
|
||||||
namespace ProjectExplorer {
|
namespace ProjectExplorer {
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------
|
||||||
|
// Helpers
|
||||||
|
// --------------------------------------------------------------------------
|
||||||
|
|
||||||
|
static Abi macAbiForCpu(quint32 type) {
|
||||||
|
switch (type) {
|
||||||
|
case 7: // CPU_TYPE_X86, CPU_TYPE_I386
|
||||||
|
return Abi(Abi::X86Architecture, Abi::MacOS, Abi::GenericMacFlavor, Abi::MachOFormat, 32);
|
||||||
|
case 0x01000000 + 7: // CPU_TYPE_X86_64
|
||||||
|
return Abi(Abi::X86Architecture, Abi::MacOS, Abi::GenericMacFlavor, Abi::MachOFormat, 64);
|
||||||
|
case 18: // CPU_TYPE_POWERPC
|
||||||
|
return Abi(Abi::PowerPCArchitecture, Abi::MacOS, Abi::GenericMacFlavor, Abi::MachOFormat, 32);
|
||||||
|
case 0x01000000 + 18: // CPU_TYPE_POWERPC64
|
||||||
|
return Abi(Abi::PowerPCArchitecture, Abi::MacOS, Abi::GenericMacFlavor, Abi::MachOFormat, 32);
|
||||||
|
case 12: // CPU_TYPE_ARM
|
||||||
|
return Abi(Abi::ArmArchitecture, Abi::MacOS, Abi::GenericMacFlavor, Abi::MachOFormat, 32);
|
||||||
|
default:
|
||||||
|
return Abi();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static QList<Abi> abiOf(const QByteArray &data)
|
||||||
|
{
|
||||||
|
QList<Abi> result;
|
||||||
|
|
||||||
|
if (data.size() >= 20
|
||||||
|
&& static_cast<unsigned char>(data.at(0)) == 0x7f && static_cast<unsigned char>(data.at(1)) == 'E'
|
||||||
|
&& static_cast<unsigned char>(data.at(2)) == 'L' && static_cast<unsigned char>(data.at(3)) == 'F') {
|
||||||
|
// ELF format:
|
||||||
|
quint16 machine = (data.at(19) << 8) + data.at(18);
|
||||||
|
switch (machine) {
|
||||||
|
case 3: // EM_386
|
||||||
|
result.append(Abi(Abi::X86Architecture, Abi::LinuxOS, Abi::GenericLinuxFlavor, Abi::ElfFormat, 32));
|
||||||
|
break;
|
||||||
|
case 8: // EM_MIPS
|
||||||
|
result.append(Abi(Abi::MipsArcitecture, Abi::LinuxOS, Abi::GenericLinuxFlavor, Abi::ElfFormat, 32));
|
||||||
|
break;
|
||||||
|
case 20: // EM_PPC
|
||||||
|
result.append(Abi(Abi::PowerPCArchitecture, Abi::LinuxOS, Abi::GenericLinuxFlavor, Abi::ElfFormat, 32));
|
||||||
|
break;
|
||||||
|
case 21: // EM_PPC64
|
||||||
|
result.append(Abi(Abi::PowerPCArchitecture, Abi::LinuxOS, Abi::GenericLinuxFlavor, Abi::ElfFormat, 64));
|
||||||
|
break;
|
||||||
|
case 62: // EM_X86_64
|
||||||
|
result.append(Abi(Abi::X86Architecture, Abi::LinuxOS, Abi::GenericLinuxFlavor, Abi::ElfFormat, 64));
|
||||||
|
break;
|
||||||
|
case 50: // EM_IA_64
|
||||||
|
result.append(Abi(Abi::ItaniumArchitecture, Abi::LinuxOS, Abi::GenericLinuxFlavor, Abi::ElfFormat, 64));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
;;
|
||||||
|
}
|
||||||
|
} else if (data.size() >= 8
|
||||||
|
&& (static_cast<unsigned char>(data.at(0)) == 0xce || static_cast<unsigned char>(data.at(0)) == 0xcf)
|
||||||
|
&& static_cast<unsigned char>(data.at(1)) == 0xfa
|
||||||
|
&& static_cast<unsigned char>(data.at(2)) == 0xed && static_cast<unsigned char>(data.at(3)) == 0xfe) {
|
||||||
|
// Mach-O format (Mac non-fat binary, 32 and 64bit magic)
|
||||||
|
quint32 type = (data.at(7) << 24) + (data.at(6) << 16) + (data.at(5) << 8) + data.at(4);
|
||||||
|
result.append(macAbiForCpu(type));
|
||||||
|
} else if (data.size() >= 8
|
||||||
|
&& static_cast<unsigned char>(data.at(0)) == 0xca && static_cast<unsigned char>(data.at(1)) == 0xfe
|
||||||
|
&& static_cast<unsigned char>(data.at(2)) == 0xba && static_cast<unsigned char>(data.at(3)) == 0xbe) {
|
||||||
|
// Mac fat binary:
|
||||||
|
quint32 count = (data.at(4) << 24) + (data.at(5) << 16) + (data.at(6) << 8) + data.at(7);
|
||||||
|
int pos = 8;
|
||||||
|
for (quint32 i = 0; i < count; ++i) {
|
||||||
|
if (data.size() <= pos + 4)
|
||||||
|
break;
|
||||||
|
|
||||||
|
quint32 type = (data.at(pos) << 24) + (data.at(pos + 1) << 16) + (data.at(pos + 2) << 8) + data.at(pos + 3);
|
||||||
|
result.append(macAbiForCpu(type));
|
||||||
|
pos += 20;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Windows PE
|
||||||
|
// Windows can have its magic bytes everywhere...
|
||||||
|
int pePos = data.indexOf("PE\0\0");
|
||||||
|
if (pePos >= 0 && pePos + 72 < data.size()) {
|
||||||
|
Abi::Architecture arch = Abi::UnknownArchitecture;
|
||||||
|
Abi::OSFlavor flavor = Abi::UnknownFlavor;
|
||||||
|
int width = 0;
|
||||||
|
|
||||||
|
// Get machine field from COFF file header
|
||||||
|
quint16 machine = (data.at(pePos + 5) << 8) + data.at(pePos + 4);
|
||||||
|
switch (machine) {
|
||||||
|
case 0x8664: // x86_64
|
||||||
|
arch = Abi::X86Architecture;
|
||||||
|
width = 64;
|
||||||
|
break;
|
||||||
|
case 0x014c: // i386
|
||||||
|
arch = Abi::X86Architecture;
|
||||||
|
width = 32;
|
||||||
|
break;
|
||||||
|
case 0x0200: // ia64
|
||||||
|
arch = Abi::ItaniumArchitecture;
|
||||||
|
width = 64;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get Major and Minor Image Version from optional header fields
|
||||||
|
quint32 image = (data.at(pePos + 71) << 24) + (data.at(pePos + 70) << 16)
|
||||||
|
+ (data.at(pePos + 69) << 8) + data.at(pePos + 68);
|
||||||
|
if (image == 1) // Image is 1 for mingw and 4.something for MSVC
|
||||||
|
flavor = Abi::WindowsMSysFlavor;
|
||||||
|
else
|
||||||
|
flavor = Abi::WindowsMsvcFlavor;
|
||||||
|
|
||||||
|
if (arch != Abi::UnknownArchitecture && flavor != Abi::UnknownFlavor && width != 0)
|
||||||
|
result.append(Abi(arch, Abi::WindowsOS, flavor, Abi::PEFormat, width));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------
|
||||||
|
// Abi
|
||||||
|
// --------------------------------------------------------------------------
|
||||||
|
|
||||||
Abi::Abi(const Architecture &a, const OS &o,
|
Abi::Abi(const Architecture &a, const OS &o,
|
||||||
const OSFlavor &of, const BinaryFormat &f, unsigned char w) :
|
const OSFlavor &of, const BinaryFormat &f, unsigned char w) :
|
||||||
m_architecture(a), m_os(o), m_osFlavor(of), m_binaryFormat(f), m_wordWidth(w)
|
m_architecture(a), m_os(o), m_osFlavor(of), m_binaryFormat(f), m_wordWidth(w)
|
||||||
@@ -325,23 +443,6 @@ Abi Abi::hostAbi()
|
|||||||
return Abi(arch, os, subos, format, QSysInfo::WordSize);
|
return Abi(arch, os, subos, format, QSysInfo::WordSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Abi macAbiForCpu(quint32 type) {
|
|
||||||
switch (type) {
|
|
||||||
case 7: // CPU_TYPE_X86, CPU_TYPE_I386
|
|
||||||
return Abi(Abi::X86Architecture, Abi::MacOS, Abi::GenericMacFlavor, Abi::MachOFormat, 32);
|
|
||||||
case 0x01000000 + 7: // CPU_TYPE_X86_64
|
|
||||||
return Abi(Abi::X86Architecture, Abi::MacOS, Abi::GenericMacFlavor, Abi::MachOFormat, 64);
|
|
||||||
case 18: // CPU_TYPE_POWERPC
|
|
||||||
return Abi(Abi::PowerPCArchitecture, Abi::MacOS, Abi::GenericMacFlavor, Abi::MachOFormat, 32);
|
|
||||||
case 0x01000000 + 18: // CPU_TYPE_POWERPC64
|
|
||||||
return Abi(Abi::PowerPCArchitecture, Abi::MacOS, Abi::GenericMacFlavor, Abi::MachOFormat, 32);
|
|
||||||
case 12: // CPU_TYPE_ARM
|
|
||||||
return Abi(Abi::ArmArchitecture, Abi::MacOS, Abi::GenericMacFlavor, Abi::MachOFormat, 32);
|
|
||||||
default:
|
|
||||||
return Abi();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<Abi> Abi::abisOfBinary(const QString &path)
|
QList<Abi> Abi::abisOfBinary(const QString &path)
|
||||||
{
|
{
|
||||||
QList<Abi> result;
|
QList<Abi> result;
|
||||||
@@ -354,94 +455,42 @@ QList<Abi> Abi::abisOfBinary(const QString &path)
|
|||||||
|
|
||||||
f.open(QFile::ReadOnly);
|
f.open(QFile::ReadOnly);
|
||||||
QByteArray data = f.read(1024);
|
QByteArray data = f.read(1024);
|
||||||
f.close();
|
if (data.size() >= 67
|
||||||
|
&& static_cast<unsigned char>(data.at(0)) == '!' && static_cast<unsigned char>(data.at(1)) == '<'
|
||||||
|
&& static_cast<unsigned char>(data.at(2)) == 'a' && static_cast<unsigned char>(data.at(3)) == 'r'
|
||||||
|
&& static_cast<unsigned char>(data.at(4)) == 'c' && static_cast<unsigned char>(data.at(5)) == 'h'
|
||||||
|
&& static_cast<unsigned char>(data.at(6)) == '>' && static_cast<unsigned char>(data.at(7)) == 0x0a) {
|
||||||
|
// We got an ar file: possibly a static lib for ELF or Mach-O
|
||||||
|
|
||||||
if (data.size() >= 20
|
data = data.mid(8); // Cut of ar file magic
|
||||||
&& static_cast<unsigned char>(data.at(0)) == 0x7f && static_cast<unsigned char>(data.at(1)) == 'E'
|
quint64 offset = 8;
|
||||||
&& static_cast<unsigned char>(data.at(2)) == 'L' && static_cast<unsigned char>(data.at(3)) == 'F') {
|
|
||||||
// ELF format:
|
|
||||||
quint16 machine = (data.at(19) << 8) + data.at(18);
|
|
||||||
switch (machine) {
|
|
||||||
case 3: // EM_386
|
|
||||||
result.append(Abi(Abi::X86Architecture, Abi::LinuxOS, Abi::GenericLinuxFlavor, Abi::ElfFormat, 32));
|
|
||||||
break;
|
|
||||||
case 8: // EM_MIPS
|
|
||||||
result.append(Abi(Abi::MipsArcitecture, Abi::LinuxOS, Abi::GenericLinuxFlavor, Abi::ElfFormat, 32));
|
|
||||||
break;
|
|
||||||
case 20: // EM_PPC
|
|
||||||
result.append(Abi(Abi::PowerPCArchitecture, Abi::LinuxOS, Abi::GenericLinuxFlavor, Abi::ElfFormat, 32));
|
|
||||||
break;
|
|
||||||
case 21: // EM_PPC64
|
|
||||||
result.append(Abi(Abi::PowerPCArchitecture, Abi::LinuxOS, Abi::GenericLinuxFlavor, Abi::ElfFormat, 64));
|
|
||||||
break;
|
|
||||||
case 62: // EM_X86_64
|
|
||||||
result.append(Abi(Abi::X86Architecture, Abi::LinuxOS, Abi::GenericLinuxFlavor, Abi::ElfFormat, 64));
|
|
||||||
break;
|
|
||||||
case 50: // EM_IA_64
|
|
||||||
result.append(Abi(Abi::ItaniumArchitecture, Abi::LinuxOS, Abi::GenericLinuxFlavor, Abi::ElfFormat, 64));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
;;
|
|
||||||
}
|
|
||||||
} else if (data.size() >= 8
|
|
||||||
&& (static_cast<unsigned char>(data.at(0)) == 0xce || static_cast<unsigned char>(data.at(0)) == 0xcf)
|
|
||||||
&& static_cast<unsigned char>(data.at(1)) == 0xfa
|
|
||||||
&& static_cast<unsigned char>(data.at(2)) == 0xed && static_cast<unsigned char>(data.at(3)) == 0xfe) {
|
|
||||||
// Mach-O format (Mac non-fat binary, 32 and 64bit magic)
|
|
||||||
quint32 type = (data.at(7) << 24) + (data.at(6) << 16) + (data.at(5) << 8) + data.at(4);
|
|
||||||
result.append(macAbiForCpu(type));
|
|
||||||
} else if (data.size() >= 8
|
|
||||||
&& static_cast<unsigned char>(data.at(0)) == 0xca && static_cast<unsigned char>(data.at(1)) == 0xfe
|
|
||||||
&& static_cast<unsigned char>(data.at(2)) == 0xba && static_cast<unsigned char>(data.at(3)) == 0xbe) {
|
|
||||||
// Mac fat binary:
|
|
||||||
quint32 count = (data.at(4) << 24) + (data.at(5) << 16) + (data.at(6) << 8) + data.at(7);
|
|
||||||
int pos = 8;
|
|
||||||
for (quint32 i = 0; i < count; ++i) {
|
|
||||||
if (data.size() <= pos + 4)
|
|
||||||
break;
|
|
||||||
|
|
||||||
quint32 type = (data.at(pos) << 24) + (data.at(pos + 1) << 16) + (data.at(pos + 2) << 8) + data.at(pos + 3);
|
while (!data.isEmpty()) {
|
||||||
result.append(macAbiForCpu(type));
|
if (data.at(58) != 0x60 || data.at(59) != 0x0a) {
|
||||||
pos += 20;
|
qWarning() << path << ": Thought it was an ar-file, but it is not!";
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Windows PE
|
|
||||||
// Windows can have its magic bytes everywhere...
|
|
||||||
int pePos = data.indexOf("PE\0\0");
|
|
||||||
if (pePos >= 0 && pePos + 72 < data.size()) {
|
|
||||||
Architecture arch = UnknownArchitecture;
|
|
||||||
OSFlavor flavor = UnknownFlavor;
|
|
||||||
int width = 0;
|
|
||||||
|
|
||||||
// Get machine field from COFF file header
|
|
||||||
quint16 machine = (data.at(pePos + 5) << 8) + data.at(pePos + 4);
|
|
||||||
switch (machine) {
|
|
||||||
case 0x8664: // x86_64
|
|
||||||
arch = Abi::X86Architecture;
|
|
||||||
width = 64;
|
|
||||||
break;
|
|
||||||
case 0x014c: // i386
|
|
||||||
arch = Abi::X86Architecture;
|
|
||||||
width = 32;
|
|
||||||
break;
|
|
||||||
case 0x0200: // ia64
|
|
||||||
arch = Abi::ItaniumArchitecture;
|
|
||||||
width = 64;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get Major and Minor Image Version from optional header fields
|
const QString fileName = QString::fromLocal8Bit(data.mid(0, 16));
|
||||||
quint32 image = (data.at(pePos + 71) << 24) + (data.at(pePos + 70) << 16)
|
quint64 fileNameOffset = 0;
|
||||||
+ (data.at(pePos + 69) << 8) + data.at(pePos + 68);
|
if (fileName.startsWith(QLatin1String("#1/")))
|
||||||
if (image == 1) // Image is 1 for mingw and 4.something for MSVC
|
fileNameOffset = fileName.mid(3).toInt();
|
||||||
flavor = WindowsMSysFlavor;
|
const QString fileLength = QString::fromAscii(data.mid(48, 10));
|
||||||
else
|
|
||||||
flavor = WindowsMsvcFlavor;
|
|
||||||
|
|
||||||
if (arch != UnknownArchitecture && flavor != UnknownFlavor && width != 0)
|
data = data.mid(60 + fileNameOffset);
|
||||||
result.append(Abi(arch, WindowsOS, flavor, PEFormat, width));
|
offset += fileLength.toInt() + 60 /* header */;
|
||||||
|
result = abiOf(data);
|
||||||
|
if (!result.isEmpty())
|
||||||
|
break;
|
||||||
|
|
||||||
|
f.seek(offset);
|
||||||
|
data = f.read(1024);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
result = abiOf(data);
|
||||||
}
|
}
|
||||||
|
f.close();
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1591,6 +1591,7 @@ QString QtVersion::qtCorePath() const
|
|||||||
dirs << QDir(libraryInstallPath()) << QDir(versionInfo().value(QLatin1String("QT_INSTALL_BINS")));
|
dirs << QDir(libraryInstallPath()) << QDir(versionInfo().value(QLatin1String("QT_INSTALL_BINS")));
|
||||||
foreach (const QDir &d, dirs) {
|
foreach (const QDir &d, dirs) {
|
||||||
QFileInfoList infoList = d.entryInfoList();
|
QFileInfoList infoList = d.entryInfoList();
|
||||||
|
QFileInfoList staticLibs;
|
||||||
foreach (const QFileInfo &info, infoList) {
|
foreach (const QFileInfo &info, infoList) {
|
||||||
const QString file = info.fileName();
|
const QString file = info.fileName();
|
||||||
if (info.isDir()
|
if (info.isDir()
|
||||||
@@ -1600,14 +1601,21 @@ QString QtVersion::qtCorePath() const
|
|||||||
const QString libName = file.left(file.lastIndexOf('.'));
|
const QString libName = file.left(file.lastIndexOf('.'));
|
||||||
return info.absoluteFilePath() + '/' + libName;
|
return info.absoluteFilePath() + '/' + libName;
|
||||||
}
|
}
|
||||||
if (info.isReadable()
|
if (info.isReadable()) {
|
||||||
&& (file.startsWith(QLatin1String("libQtCore"))
|
if (file.startsWith(QLatin1String("libQtCore"))
|
||||||
|| file.startsWith(QLatin1String("QtCore")))
|
|| file.startsWith(QLatin1String("QtCore"))) {
|
||||||
&& (file.endsWith(QLatin1String(".dll"))
|
// Only handle static libs if we can not find dynamic ones:
|
||||||
|| file.endsWith(QString::fromLatin1(".so.") + qtVersionString()))) {
|
if (file.endsWith(".a"))
|
||||||
return info.absoluteFilePath();
|
staticLibs.append(file);
|
||||||
|
else if (file.endsWith(QLatin1String(".dll"))
|
||||||
|
|| file.endsWith(QString::fromLatin1(".so.") + qtVersionString()))
|
||||||
|
return info.absoluteFilePath();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Return path to first static library found:
|
||||||
|
if (!staticLibs.isEmpty())
|
||||||
|
return staticLibs.at(0).absoluteFilePath();
|
||||||
}
|
}
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user