diff --git a/src/plugins/projectexplorer/abi.cpp b/src/plugins/projectexplorer/abi.cpp index b95eae4734229ec097c60fa8b39b05b7b78d0784..aae6074e7b3125da0de5388226c402672e677e7d 100644 --- a/src/plugins/projectexplorer/abi.cpp +++ b/src/plugins/projectexplorer/abi.cpp @@ -41,6 +41,124 @@ 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, const OSFlavor &of, const BinaryFormat &f, unsigned char 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); } -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> result; @@ -354,94 +455,42 @@ QList<Abi> Abi::abisOfBinary(const QString &path) f.open(QFile::ReadOnly); QByteArray data = f.read(1024); - f.close(); - - 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) + 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 + + data = data.mid(8); // Cut of ar file magic + quint64 offset = 8; + + while (!data.isEmpty()) { + if (data.at(58) != 0x60 || data.at(59) != 0x0a) { + qWarning() << path << ": Thought it was an ar-file, but it is not!"; 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()) { - Architecture arch = UnknownArchitecture; - OSFlavor flavor = UnknownFlavor; - int width = 0; + const QString fileName = QString::fromLocal8Bit(data.mid(0, 16)); + quint64 fileNameOffset = 0; + if (fileName.startsWith(QLatin1String("#1/"))) + fileNameOffset = fileName.mid(3).toInt(); + const QString fileLength = QString::fromAscii(data.mid(48, 10)); - // 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; + data = data.mid(60 + fileNameOffset); + offset += fileLength.toInt() + 60 /* header */; + result = abiOf(data); + if (!result.isEmpty()) 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 = WindowsMSysFlavor; - else - flavor = WindowsMsvcFlavor; - if (arch != UnknownArchitecture && flavor != UnknownFlavor && width != 0) - result.append(Abi(arch, WindowsOS, flavor, PEFormat, width)); + f.seek(offset); + data = f.read(1024); } + } else { + result = abiOf(data); } + f.close(); + return result; } diff --git a/src/plugins/qt4projectmanager/qtversionmanager.cpp b/src/plugins/qt4projectmanager/qtversionmanager.cpp index 710ea79998ba92943843c63c43c56a9977460369..95f80f2afb22e37fbdfecc510be5414e70e55fdd 100644 --- a/src/plugins/qt4projectmanager/qtversionmanager.cpp +++ b/src/plugins/qt4projectmanager/qtversionmanager.cpp @@ -1591,6 +1591,7 @@ QString QtVersion::qtCorePath() const dirs << QDir(libraryInstallPath()) << QDir(versionInfo().value(QLatin1String("QT_INSTALL_BINS"))); foreach (const QDir &d, dirs) { QFileInfoList infoList = d.entryInfoList(); + QFileInfoList staticLibs; foreach (const QFileInfo &info, infoList) { const QString file = info.fileName(); if (info.isDir() @@ -1600,14 +1601,21 @@ QString QtVersion::qtCorePath() const const QString libName = file.left(file.lastIndexOf('.')); return info.absoluteFilePath() + '/' + libName; } - if (info.isReadable() - && (file.startsWith(QLatin1String("libQtCore")) - || file.startsWith(QLatin1String("QtCore"))) - && (file.endsWith(QLatin1String(".dll")) - || file.endsWith(QString::fromLatin1(".so.") + qtVersionString()))) { - return info.absoluteFilePath(); + if (info.isReadable()) { + if (file.startsWith(QLatin1String("libQtCore")) + || file.startsWith(QLatin1String("QtCore"))) { + // Only handle static libs if we can not find dynamic ones: + if (file.endsWith(".a")) + 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(); }