// Detect Clang-cl on top of MSVC2015 or MSVC2013. static void detectClangClToolChain(QList<ToolChain *> *list) { #ifdef Q_OS_WIN64 const char registryNode[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\LLVM\\LLVM"; #else const char registryNode[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\LLVM\\LLVM"; #endif const QSettings registry(QLatin1String(registryNode), QSettings::NativeFormat); if (registry.status() != QSettings::NoError) return; const QString path = QDir::cleanPath(registry.value(QStringLiteral(".")).toString()); if (path.isEmpty()) return; const unsigned char wordWidth = Utils::is64BitWindowsBinary(path + QStringLiteral("/bin/") + QLatin1String(clangClBinary)) ? 64 : 32; const ToolChain *toolChain = findMsvcToolChain(*list, wordWidth, Abi::WindowsMsvc2015Flavor); if (!toolChain) toolChain = findMsvcToolChain(*list, wordWidth, Abi::WindowsMsvc2013Flavor); if (!toolChain) { qWarning("Unable to find a suitable MSVC version for \"%s\".", qPrintable(QDir::toNativeSeparators(path))); return; } const MsvcToolChain *msvcToolChain = static_cast<const MsvcToolChain *>(toolChain); const Abi targetAbi = msvcToolChain->targetAbi(); const QString name = QStringLiteral("LLVM ") + QString::number(wordWidth) + QStringLiteral("bit based on ") + Abi::toString(targetAbi.osFlavor()).toUpper(); list->append(new ClangClToolChain(name, path, targetAbi, msvcToolChain->varsBat(), msvcToolChain->varsBatArg(), ToolChain::AutoDetection)); }
void ProfileChooser::init(bool hostAbiOnly) { const Abi hostAbi = Abi::hostAbi(); foreach (const Profile *st, ProfileManager::instance()->profiles()) { if (!st->isValid()) continue; ToolChain *tc = ToolChainProfileInformation::toolChain(st); if (!tc) continue; const Abi abi = tc->targetAbi(); if (hostAbiOnly && hostAbi.os() != abi.os()) continue; const QString debuggerCommand = DebuggerProfileInformation::debuggerCommand(st).toString(); if (debuggerCommand.isEmpty()) continue; const QString completeBase = QFileInfo(debuggerCommand).completeBaseName(); const QString name = tr("%1 (%2)").arg(st->displayName(), completeBase); addItem(name, qVariantFromValue(st->id())); QString debugger = QDir::toNativeSeparators(debuggerCommand); debugger.replace(QString(QLatin1Char(' ')), QLatin1String(" ")); QString toolTip = tr("<html><head/><body><table>" "<tr><td>ABI:</td><td><i>%1</i></td></tr>" "<tr><td>Debugger:</td><td>%2</td></tr>") .arg(st->displayName(), QDir::toNativeSeparators(debugger)); setItemData(count() - 1, toolTip, Qt::ToolTipRole); } setEnabled(count() > 1); }
// Return the set of physical registers implicitly accessed (used or defined) // TODO: t4779515: replace this, and other switches, with logic using // attributes, instead of hardcoded opcode names. void getEffects(const Abi& abi, const Vinstr& i, RegSet& uses, RegSet& defs) { uses = defs = RegSet(); switch (i.op) { case Vinstr::mccall: case Vinstr::call: case Vinstr::callm: case Vinstr::callr: defs = abi.all() - abi.calleeSaved; break; case Vinstr::callstub: defs = i.callstub_.kills; break; case Vinstr::bindcall: case Vinstr::contenter: defs = abi.all(); break; case Vinstr::cqo: uses = RegSet(rax); defs = RegSet(rdx); break; case Vinstr::idiv: uses = defs = RegSet(rax).add(rdx); break; case Vinstr::shlq: case Vinstr::sarq: uses = RegSet(rcx); break; default: break; } }
static ToolChain *findMsvcToolChain(const QList<ToolChain *> &list, unsigned char wordWidth, Abi::OSFlavor flavor) { return Utils::findOrDefault(list, [wordWidth, flavor] (const ToolChain *tc) { const Abi abi = tc->targetAbi(); return abi.osFlavor() == flavor && wordWidth == abi.wordWidth();} ); }
void getEffects(const Abi& abi, const Vinstr& i, RegSet& uses, RegSet& across, RegSet& defs) { uses = defs = across = RegSet(); switch (i.op) { case Vinstr::mccall: case Vinstr::call: case Vinstr::callm: case Vinstr::callr: defs = abi.all() - abi.calleeSaved; switch (arch()) { case Arch::ARM: defs.add(PhysReg(arm::rLinkReg)); defs.remove(PhysReg(arm::rVmFp)); break; case Arch::X64: defs.remove(reg::rbp); break; } break; case Vinstr::bindcall: defs = abi.all(); switch (arch()) { case Arch::ARM: break; case Arch::X64: defs.remove(x64::rVmTl); break; } break; case Vinstr::contenter: case Vinstr::callstub: defs = abi.all(); switch (arch()) { case Arch::ARM: defs.remove(PhysReg(arm::rVmFp)); break; case Arch::X64: defs -= reg::rbp | x64::rVmTl; break; } break; case Vinstr::cqo: uses = RegSet(reg::rax); defs = reg::rax | reg::rdx; break; case Vinstr::idiv: uses = defs = reg::rax | reg::rdx; break; case Vinstr::shlq: case Vinstr::sarq: across = RegSet(reg::rcx); break; // arm instrs case Vinstr::hostcall: defs = (abi.all() - abi.calleeSaved) | RegSet(PhysReg(arm::rHostCallReg)); break; case Vinstr::vcall: case Vinstr::vinvoke: case Vinstr::vcallstub: always_assert(false && "Unsupported instruction in vxls"); default: break; } }
QList<ToolChain *> AndroidToolChainFactory::autodetectToolChainsForNdk(const FileName &ndkPath, const QList<ToolChain *> &alreadyKnown) { QList<ToolChain *> result; if (ndkPath.isEmpty()) return result; QRegExp versionRegExp(NDKGccVersionRegExp); FileName path = ndkPath; QDirIterator it(path.appendPath(QLatin1String("toolchains")).toString(), QStringList() << QLatin1String("*"), QDir::Dirs); QHash<Abi, QList<AndroidToolChain *>> newestToolChainForArch; while (it.hasNext()) { const QString &fileName = FileName::fromString(it.next()).fileName(); int idx = versionRegExp.indexIn(fileName); if (idx == -1) continue; QString version = fileName.mid(idx + 1); QString platform = fileName.left(idx); Abi abi = AndroidConfig::abiForToolChainPrefix(platform); if (abi.architecture() == Abi::UnknownArchitecture) // e.g. mipsel which is not yet supported continue; QList<AndroidToolChain *> toolChainBundle; for (ToolChain::Language lang : { ToolChain::Language::Cxx, ToolChain::Language::C }) { FileName compilerPath = AndroidConfigurations::currentConfig().gccPath(abi, lang, version); AndroidToolChain *tc = findToolChain(compilerPath, lang, alreadyKnown); if (!tc) { tc = new AndroidToolChain(abi, version, lang, ToolChain::AutoDetection); tc->resetToolChain(compilerPath); } result.append(tc); toolChainBundle.append(tc); } auto it = newestToolChainForArch.constFind(abi); if (it == newestToolChainForArch.constEnd()) newestToolChainForArch.insert(abi, toolChainBundle); else if (versionCompareLess(it.value(), toolChainBundle)) newestToolChainForArch[abi] = toolChainBundle; } foreach (ToolChain *tc, result) { AndroidToolChain *atc = static_cast<AndroidToolChain *>(tc); atc->setSecondaryToolChain(!newestToolChainForArch.value(atc->targetAbi()).contains(atc)); }
QList<ToolChain *> AndroidToolChainFactory::autodetectToolChainsForNdk(const FileName &ndkPath, const QList<ToolChain *> &alreadyKnown) { QList<ToolChain *> result; if (ndkPath.isEmpty()) return result; QRegExp versionRegExp(NDKGccVersionRegExp); FileName path = ndkPath; QDirIterator it(path.appendPath(QLatin1String("toolchains")).toString(), QStringList("*"), QDir::Dirs); QHash<Abi, QList<AndroidToolChain *>> newestToolChainForArch; while (it.hasNext()) { const QString &fileName = FileName::fromString(it.next()).fileName(); int idx = versionRegExp.indexIn(fileName); if (idx == -1) continue; QString version = fileName.mid(idx + 1); QString platform = fileName.left(idx); Abi abi = AndroidConfig::abiForToolChainPrefix(platform); if (abi.architecture() == Abi::UnknownArchitecture) continue; QList<AndroidToolChain *> toolChainBundle; for (Core::Id lang : {ProjectExplorer::Constants::CXX_LANGUAGE_ID, ProjectExplorer::Constants::C_LANGUAGE_ID}) { FileName compilerPath = AndroidConfigurations::currentConfig().gccPath(abi, lang, version); AndroidToolChain *tc = findToolChain(compilerPath, lang, alreadyKnown); if (!tc || tc->originalTargetTriple().isEmpty()) { tc = new AndroidToolChain(abi, version, lang, ToolChain::AutoDetection); tc->resetToolChain(compilerPath); QTC_ASSERT(!tc->originalTargetTriple().isEmpty(), delete tc; continue); } result.append(tc); toolChainBundle.append(tc); } QTC_ASSERT(!toolChainBundle.isEmpty(), continue); auto it = newestToolChainForArch.constFind(abi); if (it == newestToolChainForArch.constEnd()) newestToolChainForArch.insert(abi, toolChainBundle); else if (versionCompareLess(it.value(), toolChainBundle)) newestToolChainForArch[abi] = toolChainBundle; }
QList<Task> BaseQtVersion::validateKit(const Kit *k) { QList<Task> result; BaseQtVersion *version = QtKitInformation::qtVersion(k); Q_ASSERT(version == this); const QList<Abi> qtAbis = version->qtAbis(); if (qtAbis.isEmpty()) // No need to test if Qt does not know anyway... return result; ToolChain *tc = ToolChainKitInformation::toolChain(k); if (tc) { Abi targetAbi = tc->targetAbi(); bool fuzzyMatch = false; bool fullMatch = false; QString qtAbiString; foreach (const Abi &qtAbi, qtAbis) { if (!qtAbiString.isEmpty()) qtAbiString.append(QLatin1Char(' ')); qtAbiString.append(qtAbi.toString()); if (!fullMatch) fullMatch = (targetAbi == qtAbi); if (!fuzzyMatch) fuzzyMatch = targetAbi.isCompatibleWith(qtAbi); } QString message; if (!fullMatch) { if (!fuzzyMatch) message = QCoreApplication::translate("BaseQtVersion", "The compiler '%1' (%2) cannot produce code for the Qt version '%3' (%4)."); else message = QCoreApplication::translate("BaseQtVersion", "The compiler '%1' (%2) may not produce code compatible with the Qt version '%3' (%4)."); message = message.arg(tc->displayName(), targetAbi.toString(), version->displayName(), qtAbiString); result << Task(fuzzyMatch ? Task::Warning : Task::Error, message, FileName(), -1, ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM); } } return result; }
void AbiWidget::setCustomAbi(const Abi ¤t) { d->m_architectureComboBox->setCurrentIndex(static_cast<int>(current.architecture())); d->m_osComboBox->setCurrentIndex(static_cast<int>(current.os())); osChanged(); for (int i = 0; i < d->m_osFlavorComboBox->count(); ++i) { if (d->m_osFlavorComboBox->itemData(i).toInt() == current.osFlavor()) { d->m_osFlavorComboBox->setCurrentIndex(i); break; } } d->m_binaryFormatComboBox->setCurrentIndex(static_cast<int>(current.binaryFormat())); for (int i = 0; i < d->m_wordWidthComboBox->count(); ++i) { if (d->m_wordWidthComboBox->itemData(i).toInt() == current.wordWidth()) { d->m_wordWidthComboBox->setCurrentIndex(i); break; } } }
MsvcToolChain::MsvcToolChain(const QString &name, const Abi &abi, const QString &varsBat, const QString &varsBatArg, bool autodetect) : ToolChain(QLatin1String(Constants::MSVC_TOOLCHAIN_ID), autodetect), m_varsBat(varsBat), m_varsBatArg(varsBatArg), m_lastEnvironment(Utils::Environment::systemEnvironment()), m_abi(abi) { Q_ASSERT(!name.isEmpty()); Q_ASSERT(!m_varsBat.isEmpty()); Q_ASSERT(QFileInfo(m_varsBat).exists()); Q_ASSERT(abi.os() == Abi::WindowsOS); Q_ASSERT(abi.binaryFormat() == Abi::PEFormat); Q_ASSERT(abi.osFlavor() != Abi::WindowsMSysFlavor); setId(QString::fromLatin1("%1:%2.%3.%4").arg(Constants::MSVC_TOOLCHAIN_ID).arg(m_varsBat) .arg(m_varsBatArg).arg(m_debuggerCommand)); setDisplayName(name); }
void AbiWidget::setCustomAbi(const Abi ¤t) { bool blocked = blockSignals(true); d->m_architectureComboBox->setCurrentIndex(static_cast<int>(current.architecture())); d->m_osComboBox->setCurrentIndex(static_cast<int>(current.os())); osChanged(); for (int i = 0; i < d->m_osFlavorComboBox->count(); ++i) { if (d->m_osFlavorComboBox->itemData(i).toInt() == current.osFlavor()) { d->m_osFlavorComboBox->setCurrentIndex(i); break; } } d->m_binaryFormatComboBox->setCurrentIndex(static_cast<int>(current.binaryFormat())); for (int i = 0; i < d->m_wordWidthComboBox->count(); ++i) { if (d->m_wordWidthComboBox->itemData(i).toInt() == current.wordWidth()) { d->m_wordWidthComboBox->setCurrentIndex(i); break; } } if (d->isCustom()) d->m_abi->setItemData(0, current.toString()); blockSignals(blocked); emit abiChanged(); }
bool Abi::isCompatibleWith(const Abi &other) const { bool isCompat = (architecture() == other.architecture() || other.architecture() == Abi::UnknownArchitecture) && (os() == other.os() || other.os() == Abi::UnknownOS) && (osFlavor() == other.osFlavor() || other.osFlavor() == Abi::UnknownFlavor) && (binaryFormat() == other.binaryFormat() || other.binaryFormat() == Abi::UnknownFormat) && ((wordWidth() == other.wordWidth() && wordWidth() != 0) || other.wordWidth() == 0); // *-linux-generic-* is compatible with *-linux-* (both ways): This is for the benefit of // people building Qt themselves using e.g. a meego toolchain. // // We leave it to the specific targets to catch filter out the tool chains that do not // work for them. if (!isCompat && (architecture() == other.architecture() || other.architecture() == Abi::UnknownArchitecture) && ((os() == other.os()) && (os() == LinuxOS)) && (osFlavor() == GenericLinuxFlavor || other.osFlavor() == GenericLinuxFlavor) && (binaryFormat() == other.binaryFormat() || other.binaryFormat() == Abi::UnknownFormat) && ((wordWidth() == other.wordWidth() && wordWidth() != 0) || other.wordWidth() == 0)) isCompat = true; if (osFlavor() == AndroidLinuxFlavor || other.osFlavor() == AndroidLinuxFlavor) isCompat = (osFlavor() == other.osFlavor() && architecture() == other.architecture()); return isCompat; }
Abi QmlProjectRunConfiguration::abi() const { Abi hostAbi = Abi::hostAbi(); return Abi(hostAbi.architecture(), hostAbi.os(), hostAbi.osFlavor(), Abi::RuntimeQmlFormat, hostAbi.wordWidth()); }
void getEffects(const Abi& abi, const Vinstr& i, RegSet& uses, RegSet& across, RegSet& defs) { uses = defs = across = RegSet(); switch (i.op) { case Vinstr::mccall: case Vinstr::call: case Vinstr::callm: case Vinstr::callr: defs = abi.all() - (abi.calleeSaved | rvmfp()); switch (arch()) { case Arch::ARM: defs.add(PhysReg(arm::rLinkReg)); break; case Arch::X64: break; case Arch::PPC64: not_implemented(); break; } break; case Vinstr::bindcall: defs = abi.all(); switch (arch()) { case Arch::ARM: break; case Arch::X64: defs.remove(rvmtl()); break; case Arch::PPC64: not_implemented(); break; } break; case Vinstr::contenter: case Vinstr::callarray: defs = abi.all() - RegSet(rvmfp()); switch (arch()) { case Arch::ARM: break; case Arch::X64: defs.remove(rvmtl()); break; case Arch::PPC64: not_implemented(); break; } break; case Vinstr::callfaststub: defs = abi.all() - abi.calleeSaved - abi.gpUnreserved; break; case Vinstr::cqo: uses = RegSet(reg::rax); defs = reg::rax | reg::rdx; break; case Vinstr::idiv: uses = defs = reg::rax | reg::rdx; break; case Vinstr::shlq: case Vinstr::sarq: across = RegSet(reg::rcx); break; // arm instrs case Vinstr::hostcall: defs = (abi.all() - abi.calleeSaved) | RegSet(PhysReg(arm::rHostCallReg)); break; case Vinstr::vcall: case Vinstr::vinvoke: case Vinstr::vcallarray: always_assert(false && "Unsupported instruction in vxls"); default: break; } }
QList<Utils::FileName> GccToolChain::suggestedMkspecList() const { Abi abi = targetAbi(); Abi host = Abi::hostAbi(); // Cross compile: Leave the mkspec alone! if (abi.architecture() != host.architecture() || abi.os() != host.os() || abi.osFlavor() != host.osFlavor()) // Note: This can fail:-( return QList<Utils::FileName>(); if (abi.os() == Abi::MacOS) { QString v = version(); // prefer versioned g++ on mac. This is required to enable building for older Mac OS versions if (v.startsWith(QLatin1String("4.0")) && m_compilerCommand.endsWith(QLatin1String("-4.0"))) return QList<Utils::FileName>() << Utils::FileName::fromString(QLatin1String("macx-g++40")); if (v.startsWith(QLatin1String("4.2")) && m_compilerCommand.endsWith(QLatin1String("-4.2"))) return QList<Utils::FileName>() << Utils::FileName::fromString(QLatin1String("macx-g++42")); return QList<Utils::FileName>() << Utils::FileName::fromString(QLatin1String("macx-g++")); } if (abi.os() == Abi::LinuxOS) { if (abi.osFlavor() != Abi::GenericLinuxFlavor) return QList<Utils::FileName>(); // most likely not a desktop, so leave the mkspec alone. if (abi.wordWidth() == host.wordWidth()) return QList<Utils::FileName>() << Utils::FileName::fromString(QLatin1String("linux-g++")); // no need to explicitly set the word width return QList<Utils::FileName>() << Utils::FileName::fromString(QLatin1String("linux-g++-") + QString::number(m_targetAbi.wordWidth())); } if (abi.os() == Abi::BsdOS && abi.osFlavor() == Abi::FreeBsdFlavor) return QList<Utils::FileName>() << Utils::FileName::fromString(QLatin1String("freebsd-g++")); return QList<Utils::FileName>(); }