/**************************************************************************** ** ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of Qt Creator. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and Digia. For licensing terms and ** conditions see http://www.qt.io/licensing. For further information ** use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Digia gives you certain additional ** rights. These rights are described in the Digia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #include "baseqtversion.h" #include "qtconfigwidget.h" #include "qmldumptool.h" #include "qtkitinformation.h" #include "qtversionmanager.h" #include "profilereader.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace Core; using namespace QtSupport; using namespace QtSupport::Internal; using namespace ProjectExplorer; using namespace Utils; static const char QTVERSIONAUTODETECTED[] = "isAutodetected"; static const char QTVERSIONAUTODETECTIONSOURCE []= "autodetectionSource"; static const char QTVERSIONQMAKEPATH[] = "QMakePath"; static const char MKSPEC_VALUE_LIBINFIX[] = "QT_LIBINFIX"; static const char MKSPEC_VALUE_NAMESPACE[] = "QT_NAMESPACE"; /////////////// // QtVersionNumber /////////////// QtVersionNumber::QtVersionNumber(int ma, int mi, int p) : majorVersion(ma), minorVersion(mi), patchVersion(p) { } QtVersionNumber::QtVersionNumber(const QString &versionString) { if (::sscanf(versionString.toLatin1().constData(), "%d.%d.%d", &majorVersion, &minorVersion, &patchVersion) != 3) majorVersion = minorVersion = patchVersion = -1; } QtVersionNumber::QtVersionNumber() { majorVersion = minorVersion = patchVersion = -1; } bool QtVersionNumber::operator <(const QtVersionNumber &b) const { if (majorVersion != b.majorVersion) return majorVersion < b.majorVersion; if (minorVersion != b.minorVersion) return minorVersion < b.minorVersion; return patchVersion < b.patchVersion; } bool QtVersionNumber::operator >(const QtVersionNumber &b) const { return b < *this; } bool QtVersionNumber::operator ==(const QtVersionNumber &b) const { return majorVersion == b.majorVersion && minorVersion == b.minorVersion && patchVersion == b.patchVersion; } bool QtVersionNumber::operator !=(const QtVersionNumber &b) const { return !(*this == b); } bool QtVersionNumber::operator <=(const QtVersionNumber &b) const { return !(*this > b); } bool QtVersionNumber::operator >=(const QtVersionNumber &b) const { return b <= *this; } /////////////// // BaseQtVersion /////////////// int BaseQtVersion::getUniqueId() { return QtVersionManager::getUniqueId(); } BaseQtVersion::BaseQtVersion(const FileName &qmakeCommand, bool isAutodetected, const QString &autodetectionSource) : m_id(getUniqueId()), m_isAutodetected(isAutodetected), m_hasQmlDump(false), m_mkspecUpToDate(false), m_mkspecReadUpToDate(false), m_defaultConfigIsDebug(true), m_defaultConfigIsDebugAndRelease(true), m_frameworkBuild(false), m_versionInfoUpToDate(false), m_installed(true), m_hasExamples(false), m_hasDemos(false), m_hasDocumentation(false), m_qmakeIsExecutable(true), m_hasQtAbis(false), m_autodetectionSource(autodetectionSource) { ctor(qmakeCommand); } BaseQtVersion::BaseQtVersion(const BaseQtVersion &other) : m_id(other.m_id), m_isAutodetected(other.m_isAutodetected), m_hasQmlDump(other.m_hasQmlDump), m_mkspecUpToDate(other.m_mkspecUpToDate), m_mkspecReadUpToDate(other.m_mkspecReadUpToDate), m_defaultConfigIsDebug(other.m_defaultConfigIsDebug), m_defaultConfigIsDebugAndRelease(other.m_defaultConfigIsDebugAndRelease), m_frameworkBuild(other.m_frameworkBuild), m_versionInfoUpToDate(other.m_versionInfoUpToDate), m_installed(other.m_installed), m_hasExamples(other.m_hasExamples), m_hasDemos(other.m_hasDemos), m_hasDocumentation(other.m_hasDocumentation), m_qmakeIsExecutable(other.m_qmakeIsExecutable), m_hasQtAbis(other.m_hasQtAbis), m_configValues(other.m_configValues), m_qtConfigValues(other.m_qtConfigValues), m_unexpandedDisplayName(other.m_unexpandedDisplayName), m_autodetectionSource(other.m_autodetectionSource), m_sourcePath(other.m_sourcePath), m_mkspec(other.m_mkspec), m_mkspecFullPath(other.m_mkspecFullPath), m_mkspecValues(other.m_mkspecValues), m_versionInfo(other.m_versionInfo), m_qmakeCommand(other.m_qmakeCommand), m_qtVersionString(other.m_qtVersionString), m_uicCommand(other.m_uicCommand), m_designerCommand(other.m_designerCommand), m_linguistCommand(other.m_linguistCommand), m_qmlsceneCommand(other.m_qmlsceneCommand), m_qmlviewerCommand(other.m_qmlviewerCommand), m_qtAbis(other.m_qtAbis) { setupExpander(); } BaseQtVersion::BaseQtVersion() : m_id(-1), m_isAutodetected(false), m_hasQmlDump(false), m_mkspecUpToDate(false), m_mkspecReadUpToDate(false), m_defaultConfigIsDebug(true), m_defaultConfigIsDebugAndRelease(true), m_frameworkBuild(false), m_versionInfoUpToDate(false), m_installed(true), m_hasExamples(false), m_hasDemos(false), m_hasDocumentation(false), m_qmakeIsExecutable(true), m_hasQtAbis(false) { ctor(FileName()); } void BaseQtVersion::ctor(const FileName &qmakePath) { m_qmakeCommand = qmakePath; m_designerCommand.clear(); m_linguistCommand.clear(); m_qmlviewerCommand.clear(); m_uicCommand.clear(); m_mkspecUpToDate = false; m_mkspecReadUpToDate = false; m_versionInfoUpToDate = false; m_hasQtAbis = false; m_qtVersionString.clear(); m_sourcePath.clear(); setupExpander(); } void BaseQtVersion::setupExpander() { m_expander.setDisplayName( QCoreApplication::translate("QtSupport::QtKitInformation", "Qt version")); m_expander.registerVariable("Qt:Version", QCoreApplication::translate("QtSupport::QtKitInformation", "The version string of the current Qt version."), [this]() { return qtVersionString(); }); m_expander.registerVariable("Qt:Type", QCoreApplication::translate("QtSupport::QtKitInformation", "The type of the current Qt version."), [this]() { return type(); }); m_expander.registerVariable("Qt:Mkspec", QCoreApplication::translate("QtSupport::QtKitInformation", "The mkspec of the current Qt version."), [this]() { return mkspec().toUserOutput(); }); // FIXME: Re-enable once we can detect expansion loops. // m_expander.registerVariable("Qt:Name", // QCoreApplication::translate("QtSupport::QtKitInformation", "The display name of the current Qt version."), // [this]() { return displayName(); }); } BaseQtVersion::~BaseQtVersion() { } QString BaseQtVersion::defaultUnexpandedDisplayName(const FileName &qmakePath, bool fromPath) { QString location; if (qmakePath.isEmpty()) { location = QCoreApplication::translate("QtVersion", ""); } else { // Deduce a description from '/foo/qt-folder/[qtbase]/bin/qmake' -> '/foo/qt-folder'. // '/usr' indicates System Qt 4.X on Linux. QDir dir = qmakePath.toFileInfo().absoluteDir(); do { const QString dirName = dir.dirName(); if (dirName == QLatin1String("usr")) { // System-installed Qt. location = QCoreApplication::translate("QtVersion", "System"); break; } location = dirName; // Also skip default checkouts named 'qt'. Parent dir might have descriptive name. if (dirName.compare(QLatin1String("bin"), Qt::CaseInsensitive) && dirName.compare(QLatin1String("qtbase"), Qt::CaseInsensitive) && dirName.compare(QLatin1String("qt"), Qt::CaseInsensitive)) { break; } } while (!dir.isRoot() && dir.cdUp()); } return fromPath ? QCoreApplication::translate("QtVersion", "Qt %{Qt:Version} in PATH (%2)").arg(location) : QCoreApplication::translate("QtVersion", "Qt %{Qt:Version} (%2)").arg(location); } FeatureSet BaseQtVersion::availableFeatures() const { FeatureSet features = FeatureSet(Constants::FEATURE_QWIDGETS) | FeatureSet(Constants::FEATURE_QT) | FeatureSet(Constants::FEATURE_QT_WEBKIT) | FeatureSet(Constants::FEATURE_QT_CONSOLE); if (qtVersion() < QtVersionNumber(5, 0, 0)) features |= FeatureSet(Constants::FEATURE_QT4); else features |= FeatureSet(Constants::FEATURE_QT5); if (qtVersion() < QtVersionNumber(4, 7, 0)) return features; features |= FeatureSet(Constants::FEATURE_QT_QUICK); features |= FeatureSet(Constants::FEATURE_QT_QUICK_1); if (qtVersion() < QtVersionNumber(4, 7, 1)) return features; features |= FeatureSet(Constants::FEATURE_QT_QUICK_1_1); if (qtVersion() < QtVersionNumber(5, 0, 0)) return features; features |= FeatureSet(Constants::FEATURE_QT_QUICK_2); features |= FeatureSet(Constants::FEATURE_QT_QUICK_2_0); if (qtVersion() < QtVersionNumber(5, 1, 0)) return features; features |= FeatureSet(Constants::FEATURE_QT_QUICK_2_1); features |= FeatureSet(Constants::FEATURE_QT_QUICK_CONTROLS); features |= FeatureSet(Constants::FEATURE_QT_QUICK_CONTROLS_1); features |= FeatureSet(Constants::FEATURE_QT_QUICK_CONTROLS_1_0); if (qtVersion() < QtVersionNumber(5, 2, 0)) return features; features |= FeatureSet(Constants::FEATURE_QT_QUICK_2_2); features |= FeatureSet(Constants::FEATURE_QT_QUICK_CONTROLS_1_1); if (qtVersion() < QtVersionNumber(5, 3, 0)) return features; features |= FeatureSet(Constants::FEATURE_QT_QUICK_2_3); features |= FeatureSet(Constants::FEATURE_QT_QUICK_CONTROLS_1_2); if (qtVersion() < QtVersionNumber(5, 4, 0)) return features; features |= FeatureSet(Constants::FEATURE_QT_QUICK_2_4); features |= FeatureSet(Constants::FEATURE_QT_QUICK_CONTROLS_1_3); features |= FeatureSet(Constants::FEATURE_QT_QUICK_UI_FILES); return features; } QString BaseQtVersion::platformName() const { return QString(); } QString BaseQtVersion::platformDisplayName() const { return platformName(); } bool BaseQtVersion::supportsPlatform(const QString &platform) const { if (platform.isEmpty()) // empty target == target independent return true; return platform == platformName(); } QList BaseQtVersion::validateKit(const Kit *k) { QList result; BaseQtVersion *version = QtKitInformation::qtVersion(k); Q_ASSERT(version == this); const QList 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; } FileName BaseQtVersion::headerPath() const { return FileName::fromUserInput(qmakeProperty("QT_INSTALL_HEADERS")); } FileName BaseQtVersion::docsPath() const { return FileName::fromUserInput(qmakeProperty("QT_INSTALL_DOCS")); } FileName BaseQtVersion::libraryPath() const { return FileName::fromUserInput(qmakeProperty("QT_INSTALL_LIBS")); } FileName BaseQtVersion::pluginPath() const { return FileName::fromUserInput(qmakeProperty("QT_INSTALL_PLUGINS")); } FileName BaseQtVersion::binPath() const { return FileName::fromUserInput(qmakeProperty("QT_HOST_BINS")); } FileName BaseQtVersion::mkspecsPath() const { FileName result = FileName::fromUserInput(qmakeProperty("QT_HOST_DATA")); if (result.isEmpty()) result = FileName::fromUserInput(qmakeProperty("QMAKE_MKSPECS")); else result.appendPath(QLatin1String("mkspecs")); return result; } QString BaseQtVersion::qtNamespace() const { ensureMkSpecParsed(); return m_mkspecValues.value(QLatin1String(MKSPEC_VALUE_NAMESPACE)); } QString BaseQtVersion::qtLibInfix() const { ensureMkSpecParsed(); return m_mkspecValues.value(QLatin1String(MKSPEC_VALUE_LIBINFIX)); } bool BaseQtVersion::isFrameworkBuild() const { ensureMkSpecParsed(); return m_frameworkBuild; } bool BaseQtVersion::hasDebugBuild() const { return m_defaultConfigIsDebug || m_defaultConfigIsDebugAndRelease; } bool BaseQtVersion::hasReleaseBuild() const { return !m_defaultConfigIsDebug || m_defaultConfigIsDebugAndRelease; } void BaseQtVersion::setId(int id) { m_id = id; } void BaseQtVersion::fromMap(const QVariantMap &map) { m_id = map.value(QLatin1String(Constants::QTVERSIONID)).toInt(); if (m_id == -1) // this happens on adding from installer, see updateFromInstaller => get a new unique id m_id = QtVersionManager::getUniqueId(); m_unexpandedDisplayName = map.value(QLatin1String(Constants::QTVERSIONNAME)).toString(); m_isAutodetected = map.value(QLatin1String(QTVERSIONAUTODETECTED)).toBool(); if (m_isAutodetected) m_autodetectionSource = map.value(QLatin1String(QTVERSIONAUTODETECTIONSOURCE)).toString(); QString string = map.value(QLatin1String(QTVERSIONQMAKEPATH)).toString(); if (string.startsWith(QLatin1Char('~'))) string.remove(0, 1).prepend(QDir::homePath()); QFileInfo fi(string); if (BuildableHelperLibrary::isQtChooser(fi)) { // we don't want to treat qtchooser as a normal qmake // see e.g. QTCREATORBUG-9841, also this lead to users changing what // qtchooser forwards too behind our backs, which will inadvertly lead to bugs string = BuildableHelperLibrary::qtChooserToQmakePath(fi.symLinkTarget()); } ctor(FileName::fromString(string)); } QVariantMap BaseQtVersion::toMap() const { QVariantMap result; result.insert(QLatin1String(Constants::QTVERSIONID), uniqueId()); result.insert(QLatin1String(Constants::QTVERSIONNAME), unexpandedDisplayName()); result.insert(QLatin1String(QTVERSIONAUTODETECTED), isAutodetected()); if (isAutodetected()) result.insert(QLatin1String(QTVERSIONAUTODETECTIONSOURCE), autodetectionSource()); result.insert(QLatin1String(QTVERSIONQMAKEPATH), qmakeCommand().toString()); return result; } bool BaseQtVersion::isValid() const { if (uniqueId() == -1 || displayName().isEmpty()) return false; updateVersionInfo(); updateMkspec(); return !qmakeCommand().isEmpty() && m_installed && !qmakeProperty("QT_HOST_BINS").isNull() && !m_mkspecFullPath.isEmpty() && m_qmakeIsExecutable; } QString BaseQtVersion::invalidReason() const { if (displayName().isEmpty()) return QCoreApplication::translate("QtVersion", "Qt version has no name"); if (qmakeCommand().isEmpty()) return QCoreApplication::translate("QtVersion", "No qmake path set"); if (!m_qmakeIsExecutable) return QCoreApplication::translate("QtVersion", "qmake does not exist or is not executable"); if (!m_installed) return QCoreApplication::translate("QtVersion", "Qt version is not properly installed, please run make install"); if (qmakeProperty("QT_HOST_BINS").isNull()) return QCoreApplication::translate("QtVersion", "Could not determine the path to the binaries of the Qt installation, maybe the qmake path is wrong?"); if (m_mkspecUpToDate && m_mkspecFullPath.isEmpty()) return QCoreApplication::translate("QtVersion", "The default mkspec symlink is broken."); return QString(); } QStringList BaseQtVersion::warningReason() const { QStringList ret; if (qtAbis().isEmpty()) ret << QCoreApplication::translate("QtVersion", "ABI detection failed: Make sure to use a matching compiler when building."); if (m_versionInfo.value(QLatin1String("QT_INSTALL_PREFIX/get")) != m_versionInfo.value(QLatin1String("QT_INSTALL_PREFIX"))) { ret << QCoreApplication::translate("QtVersion", "Non-installed -prefix build - for internal development only."); } return ret; } FileName BaseQtVersion::qmakeCommand() const { return m_qmakeCommand; } QList BaseQtVersion::qtAbis() const { if (!m_hasQtAbis) { m_qtAbis = detectQtAbis(); m_hasQtAbis = true; } return m_qtAbis; } bool BaseQtVersion::equals(BaseQtVersion *other) { if (type() != other->type()) return false; if (uniqueId() != other->uniqueId()) return false; if (displayName() != other->displayName()) return false; if (isValid() != other->isValid()) return false; return true; } int BaseQtVersion::uniqueId() const { return m_id; } bool BaseQtVersion::isAutodetected() const { return m_isAutodetected; } QString BaseQtVersion::autodetectionSource() const { return m_autodetectionSource; } void BaseQtVersion::setAutoDetectionSource(const QString &autodetectionSource) { m_autodetectionSource = autodetectionSource; } QString BaseQtVersion::displayName() const { return m_expander.expand(m_unexpandedDisplayName); } QString BaseQtVersion::unexpandedDisplayName() const { return m_unexpandedDisplayName; } void BaseQtVersion::setUnexpandedDisplayName(const QString &name) { m_unexpandedDisplayName = name; } QString BaseQtVersion::toHtml(bool verbose) const { QString rc; QTextStream str(&rc); str << ""; str << ""; if (!isValid()) { str << ""; } else { str << ""; const QList abis = qtAbis(); if (abis.isEmpty()) { str << ""; } else { for (int i = 0; i < abis.size(); ++i) { if (i) str << ""; str << ""; } } str << ""; str << ""; str << ""; ensureMkSpecParsed(); if (!mkspecPath().isEmpty()) { if (m_defaultConfigIsDebug || m_defaultConfigIsDebugAndRelease) { str << ""; } // default config. } str << ""; if (verbose) { const QHash vInfo = versionInfo(); if (!vInfo.isEmpty()) { QStringList keys = vInfo.keys(); keys.sort(); foreach (QString variableName, keys) { const QString &value = vInfo.value(variableName); if (variableName != QLatin1String("QMAKE_MKSPECS") && !variableName.endsWith(QLatin1String("/raw"))) { bool isPath = false; if (variableName.contains(QLatin1String("_HOST_")) || variableName.contains(QLatin1String("_INSTALL_"))) { if (!variableName.endsWith(QLatin1String("/get"))) continue; variableName.chop(4); isPath = true; } else if (variableName == QLatin1String("QT_SYSROOT")) { isPath = true; } str << ""; } } } } } str << "
" << QCoreApplication::translate("BaseQtVersion", "Name:") << "" << displayName() << "
" << QCoreApplication::translate("BaseQtVersion", "Invalid Qt version") << "
" << QCoreApplication::translate("BaseQtVersion", "ABI:") << "" << Abi().toString() << "
" << abis.at(i).toString() << "
" << QCoreApplication::translate("BaseQtVersion", "Source:") << "" << sourcePath().toUserOutput() << "
" << QCoreApplication::translate("BaseQtVersion", "mkspec:") << "" << mkspec().toUserOutput() << "
" << QCoreApplication::translate("BaseQtVersion", "qmake:") << "" << m_qmakeCommand.toUserOutput() << "
" << QCoreApplication::translate("BaseQtVersion", "Default:") << "" << (m_defaultConfigIsDebug ? "debug" : "release"); if (m_defaultConfigIsDebugAndRelease) str << " debug_and_release"; str << "
" << QCoreApplication::translate("BaseQtVersion", "Version:") << "" << qtVersionString() << "
" << variableName <<  "
"; if (value.isEmpty()) isPath = false; if (isPath) { str << "" << QDir::toNativeSeparators(value) << ""; } else { str << value; } str << "
"; return rc; } void BaseQtVersion::updateSourcePath() const { if (!m_sourcePath.isEmpty()) return; updateVersionInfo(); m_sourcePath = sourcePath(m_versionInfo); } FileName BaseQtVersion::sourcePath() const { updateSourcePath(); return m_sourcePath; } QString BaseQtVersion::designerCommand() const { if (!isValid()) return QString(); if (m_designerCommand.isNull()) m_designerCommand = findQtBinary(Designer); return m_designerCommand; } QString BaseQtVersion::linguistCommand() const { if (!isValid()) return QString(); if (m_linguistCommand.isNull()) m_linguistCommand = findQtBinary(Linguist); return m_linguistCommand; } QString BaseQtVersion::qmlsceneCommand() const { if (!isValid()) return QString(); if (m_qmlsceneCommand.isNull()) m_qmlsceneCommand = findQtBinary(QmlScene); return m_qmlsceneCommand; } QString BaseQtVersion::qmlviewerCommand() const { if (!isValid()) return QString(); if (m_qmlviewerCommand.isNull()) m_qmlviewerCommand = findQtBinary(QmlViewer); return m_qmlviewerCommand; } QString BaseQtVersion::findQtBinary(Binaries binary) const { QString baseDir; if (qtVersion() < QtVersionNumber(5, 0, 0)) { baseDir = qmakeProperty("QT_HOST_BINS"); } else { ensureMkSpecParsed(); switch (binary) { case QmlScene: baseDir = m_mkspecValues.value(QLatin1String("QT.qml.bins")); break; case QmlViewer: baseDir = m_mkspecValues.value(QLatin1String("QT.declarative.bins")); break; case Designer: case Linguist: baseDir = m_mkspecValues.value(QLatin1String("QT.designer.bins")); break; case Uic: baseDir = qmakeProperty("QT_HOST_BINS"); break; default: // Can't happen Q_ASSERT(false); } } if (baseDir.isEmpty()) return QString(); if (!baseDir.endsWith(QLatin1Char('/'))) baseDir += QLatin1Char('/'); QStringList possibleCommands; switch (binary) { case QmlScene: possibleCommands << HostOsInfo::withExecutableSuffix(QLatin1String("qmlscene")); break; case QmlViewer: { if (HostOsInfo::isMacHost()) possibleCommands << QLatin1String("QMLViewer.app/Contents/MacOS/QMLViewer"); else possibleCommands << HostOsInfo::withExecutableSuffix(QLatin1String("qmlviewer")); } break; case Designer: if (HostOsInfo::isMacHost()) possibleCommands << QLatin1String("Designer.app/Contents/MacOS/Designer"); else possibleCommands << HostOsInfo::withExecutableSuffix(QLatin1String("designer")); break; case Linguist: if (HostOsInfo::isMacHost()) possibleCommands << QLatin1String("Linguist.app/Contents/MacOS/Linguist"); possibleCommands << HostOsInfo::withExecutableSuffix(QLatin1String("linguist")); break; case Uic: if (HostOsInfo::isWindowsHost()) { possibleCommands << QLatin1String("uic.exe"); } else { possibleCommands << QLatin1String("uic-qt4") << QLatin1String("uic4") << QLatin1String("uic"); } break; default: Q_ASSERT(false); } foreach (const QString &possibleCommand, possibleCommands) { const QString fullPath = baseDir + possibleCommand; if (QFileInfo(fullPath).isFile()) return QDir::cleanPath(fullPath); } return QString(); } QString BaseQtVersion::uicCommand() const { if (!isValid()) return QString(); if (!m_uicCommand.isNull()) return m_uicCommand; m_uicCommand = findQtBinary(Uic); return m_uicCommand; } void BaseQtVersion::updateMkspec() const { if (uniqueId() == -1 || m_mkspecUpToDate) return; m_mkspecUpToDate = true; m_mkspecFullPath = mkspecFromVersionInfo(versionInfo()); m_mkspec = m_mkspecFullPath; if (m_mkspecFullPath.isEmpty()) return; FileName baseMkspecDir = mkspecDirectoryFromVersionInfo(versionInfo()); if (m_mkspec.isChildOf(baseMkspecDir)) { m_mkspec = m_mkspec.relativeChildPath(baseMkspecDir); // qDebug() << "Setting mkspec to"<incRefCount(); QMakeParser parser(ProFileCacheManager::instance()->cache(), &vfs, &msgHandler); ProFileEvaluator evaluator(&option, &parser, &vfs, &msgHandler); evaluator.loadNamedSpec(mkspecPath().toString(), false); parseMkSpec(&evaluator); ProFileCacheManager::instance()->decRefCount(); } void BaseQtVersion::parseMkSpec(ProFileEvaluator *evaluator) const { m_configValues = evaluator->values(QLatin1String("CONFIG")); m_qtConfigValues = evaluator->values(QLatin1String("QT_CONFIG")); m_defaultConfigIsDebugAndRelease = false; m_frameworkBuild = false; foreach (const QString &value, m_configValues) { if (value == QLatin1String("debug")) m_defaultConfigIsDebug = true; else if (value == QLatin1String("release")) m_defaultConfigIsDebug = false; else if (value == QLatin1String("build_all")) m_defaultConfigIsDebugAndRelease = true; else if (value == QLatin1String("qt_framework")) m_frameworkBuild = true; } const QString designerBins = QLatin1String("QT.designer.bins"); const QString qmlBins = QLatin1String("QT.qml.bins"); const QString declarativeBins = QLatin1String("QT.declarative.bins"); const QString libinfix = QLatin1String(MKSPEC_VALUE_LIBINFIX); const QString ns = QLatin1String(MKSPEC_VALUE_NAMESPACE); m_mkspecValues.insert(designerBins, evaluator->value(designerBins)); m_mkspecValues.insert(qmlBins, evaluator->value(qmlBins)); m_mkspecValues.insert(declarativeBins, evaluator->value(declarativeBins)); m_mkspecValues.insert(libinfix, evaluator->value(libinfix)); m_mkspecValues.insert(ns, evaluator->value(ns)); } FileName BaseQtVersion::mkspec() const { updateMkspec(); return m_mkspec; } FileName BaseQtVersion::mkspecFor(ToolChain *tc) const { FileName versionSpec = mkspec(); if (!tc) return versionSpec; const QList tcSpecList = tc->suggestedMkspecList(); if (tcSpecList.contains(versionSpec)) return versionSpec; foreach (const FileName &tcSpec, tcSpecList) { if (hasMkspec(tcSpec)) return tcSpec; } return versionSpec; } FileName BaseQtVersion::mkspecPath() const { updateMkspec(); return m_mkspecFullPath; } bool BaseQtVersion::hasMkspec(const FileName &spec) const { QFileInfo fi; fi.setFile(QDir::fromNativeSeparators(qmakeProperty("QT_HOST_DATA")) + QLatin1String("/mkspecs/") + spec.toString()); if (fi.isDir()) return true; fi.setFile(sourcePath().toString() + QLatin1String("/mkspecs/") + spec.toString()); return fi.isDir(); } BaseQtVersion::QmakeBuildConfigs BaseQtVersion::defaultBuildConfig() const { ensureMkSpecParsed(); BaseQtVersion::QmakeBuildConfigs result = BaseQtVersion::QmakeBuildConfig(0); if (m_defaultConfigIsDebugAndRelease) result = BaseQtVersion::BuildAll; if (m_defaultConfigIsDebug) result = result | BaseQtVersion::DebugBuild; return result; } QString BaseQtVersion::qtVersionString() const { updateVersionInfo(); return m_qtVersionString; } QtVersionNumber BaseQtVersion::qtVersion() const { return QtVersionNumber(qtVersionString()); } void BaseQtVersion::updateVersionInfo() const { if (m_versionInfoUpToDate) return; if (!m_qmakeIsExecutable) return; // extract data from qmake executable m_versionInfo.clear(); m_installed = true; m_hasExamples = false; m_hasDocumentation = false; m_hasQmlDump = false; if (!queryQMakeVariables(qmakeCommand(), qmakeRunEnvironment(), &m_versionInfo)) { m_qmakeIsExecutable = false; qWarning("Cannot update Qt version information: %s cannot be run.", qPrintable(qmakeCommand().toString())); return; } m_qmakeIsExecutable = true; const QString qtInstallData = qmakeProperty(m_versionInfo, "QT_INSTALL_DATA"); const QString qtInstallBins = qmakeProperty(m_versionInfo, "QT_INSTALL_BINS"); const QString qtHeaderData = qmakeProperty(m_versionInfo, "QT_INSTALL_HEADERS"); if (!qtInstallData.isNull()) { if (!qtInstallData.isEmpty()) { m_hasQmlDump = !QmlDumpTool::toolForQtPaths(qtInstallData, qtInstallBins, qtHeaderData, false).isEmpty() || !QmlDumpTool::toolForQtPaths(qtInstallData, qtInstallBins, qtHeaderData, true).isEmpty(); } } // Now check for a qt that is configured with a prefix but not installed QString installDir = qmakeProperty(m_versionInfo, "QT_HOST_BINS"); if (!installDir.isNull()) { if (!QFileInfo::exists(installDir)) m_installed = false; } // Framework builds for Qt 4.8 don't use QT_INSTALL_HEADERS // so we don't check on mac if (!HostOsInfo::isMacHost()) { if (!qtHeaderData.isNull()) { if (!QFileInfo::exists(qtHeaderData)) m_installed = false; } } const QString qtInstallDocs = qmakeProperty(m_versionInfo, "QT_INSTALL_DOCS"); if (!qtInstallDocs.isNull()) { if (QFileInfo::exists(qtInstallDocs)) m_hasDocumentation = true; } const QString qtInstallExamples = qmakeProperty(m_versionInfo, "QT_INSTALL_EXAMPLES"); if (!qtInstallExamples.isNull()) { if (QFileInfo::exists(qtInstallExamples)) m_hasExamples = true; } const QString qtInstallDemos = qmakeProperty(m_versionInfo, "QT_INSTALL_DEMOS"); if (!qtInstallDemos.isNull()) { if (QFileInfo::exists(qtInstallDemos)) m_hasDemos = true; } m_qtVersionString = qmakeProperty(m_versionInfo, "QT_VERSION"); m_versionInfoUpToDate = true; } QHash BaseQtVersion::versionInfo() const { updateVersionInfo(); return m_versionInfo; } QString BaseQtVersion::qmakeProperty(const QHash &versionInfo, const QByteArray &name, PropertyVariant variant) { QString val = versionInfo.value(QString::fromLatin1( name + (variant == PropertyVariantGet ? "/get" : "/src"))); if (!val.isNull()) return val; return versionInfo.value(QString::fromLatin1(name)); } QString BaseQtVersion::qmakeProperty(const QByteArray &name) const { updateVersionInfo(); return qmakeProperty(m_versionInfo, name); } bool BaseQtVersion::hasDocumentation() const { updateVersionInfo(); return m_hasDocumentation; } QString BaseQtVersion::documentationPath() const { return qmakeProperty("QT_INSTALL_DOCS"); } bool BaseQtVersion::hasDemos() const { updateVersionInfo(); return m_hasDemos; } QString BaseQtVersion::demosPath() const { return qmakeProperty("QT_INSTALL_DEMOS"); } QString BaseQtVersion::frameworkInstallPath() const { if (HostOsInfo::isMacHost()) return qmakeProperty("QT_INSTALL_LIBS"); return QString(); } bool BaseQtVersion::hasExamples() const { updateVersionInfo(); return m_hasExamples; } QString BaseQtVersion::examplesPath() const { return qmakeProperty("QT_INSTALL_EXAMPLES"); } QStringList BaseQtVersion::configValues() const { ensureMkSpecParsed(); return m_configValues; } QStringList BaseQtVersion::qtConfigValues() const { ensureMkSpecParsed(); return m_qtConfigValues; } MacroExpander *BaseQtVersion::macroExpander() const { return &m_expander; } QList BaseQtVersion::systemHeaderPathes(const Kit *k) const { Q_UNUSED(k); QList result; result.append(HeaderPath(mkspecPath().toString(), HeaderPath::GlobalHeaderPath)); return result; } void BaseQtVersion::addToEnvironment(const Kit *k, Environment &env) const { Q_UNUSED(k); env.set(QLatin1String("QTDIR"), QDir::toNativeSeparators(qmakeProperty("QT_HOST_DATA"))); env.prependOrSetPath(qmakeProperty("QT_HOST_BINS")); } // Some Qt versions may require environment settings for qmake to work // // One such example is Blackberry which for some reason decided to always use the same // qmake and use environment variables embedded in their mkspecs to make that point to // the different Qt installations. Environment BaseQtVersion::qmakeRunEnvironment() const { return Environment::systemEnvironment(); } bool BaseQtVersion::hasQmlDump() const { updateVersionInfo(); return m_hasQmlDump; } bool BaseQtVersion::hasQmlDumpWithRelocatableFlag() const { return ((qtVersion() > QtVersionNumber(4, 8, 4) && qtVersion() < QtVersionNumber(5, 0, 0)) || qtVersion() >= QtVersionNumber(5, 1, 0)); } bool BaseQtVersion::needsQmlDump() const { return qtVersion() < QtVersionNumber(4, 8, 0); } Environment BaseQtVersion::qmlToolsEnvironment() const { // FIXME: This seems broken! Environment environment = Environment::systemEnvironment(); #if 0 // FIXME: Fix this! addToEnvironment(environment); #endif // add preferred tool chain, as that is how the tools are built, compare QtVersion::buildDebuggingHelperLibrary if (!qtAbis().isEmpty()) { QList alltc = ToolChainManager::findToolChains(qtAbis().at(0)); if (!alltc.isEmpty()) alltc.first()->addToEnvironment(environment); } return environment; } QString BaseQtVersion::qmlDumpTool(bool debugVersion) const { const QString qtInstallData = qmakeProperty("QT_INSTALL_DATA"); if (qtInstallData.isEmpty()) return QString(); const QString qtInstallBins = qmakeProperty("QT_INSTALL_BINS"); const QString qtHeaderData = qmakeProperty("QT_INSTALL_HEADERS"); return QmlDumpTool::toolForQtPaths(qtInstallData, qtInstallBins, qtHeaderData, debugVersion); } void BaseQtVersion::recheckDumper() { m_versionInfoUpToDate = false; } bool BaseQtVersion::supportsShadowBuilds() const { return true; } QList BaseQtVersion::reportIssuesImpl(const QString &proFile, const QString &buildDir) const { QList results; QString tmpBuildDir = QDir(buildDir).absolutePath(); if (!tmpBuildDir.endsWith(QLatin1Char('/'))) tmpBuildDir.append(QLatin1Char('/')); if (!isValid()) { //: %1: Reason for being invalid const QString msg = QCoreApplication::translate("QmakeProjectManager::QtVersion", "The Qt version is invalid: %1").arg(invalidReason()); results.append(Task(Task::Error, msg, FileName(), -1, ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM)); } QFileInfo qmakeInfo = qmakeCommand().toFileInfo(); if (!qmakeInfo.exists() || !qmakeInfo.isExecutable()) { //: %1: Path to qmake executable const QString msg = QCoreApplication::translate("QmakeProjectManager::QtVersion", "The qmake command \"%1\" was not found or is not executable.").arg(qmakeCommand().toUserOutput()); results.append(Task(Task::Error, msg, FileName(), -1, ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM)); } QString sourcePath = QFileInfo(proFile).absolutePath(); const QChar slash = QLatin1Char('/'); if (!sourcePath.endsWith(slash)) sourcePath.append(slash); if ((tmpBuildDir.startsWith(sourcePath)) && (tmpBuildDir != sourcePath) && qtVersion() < QtVersionNumber(5, 2, 0)) { const QString msg = QCoreApplication::translate("QmakeProjectManager::QtVersion", "Qmake does not support build directories below the source directory."); results.append(Task(Task::Warning, msg, FileName(), -1, ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM)); } else if (tmpBuildDir.count(slash) != sourcePath.count(slash) && qtVersion() < QtVersionNumber(4,8, 0)) { const QString msg = QCoreApplication::translate("QmakeProjectManager::QtVersion", "The build directory needs to be at the same level as the source directory."); results.append(Task(Task::Warning, msg, FileName(), -1, ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM)); } return results; } QList BaseQtVersion::reportIssues(const QString &proFile, const QString &buildDir) const { QList results = reportIssuesImpl(proFile, buildDir); Utils::sort(results); return results; } QtConfigWidget *BaseQtVersion::createConfigurationWidget() const { return 0; } static QByteArray runQmakeQuery(const FileName &binary, const Environment &env, QString *error) { QTC_ASSERT(error, return QByteArray()); const int timeOutMS = 30000; // Might be slow on some machines. // Prevent e.g. qmake 4.x on MinGW to show annoying errors about missing dll's. WindowsCrashDialogBlocker crashDialogBlocker; QProcess process; process.setEnvironment(env.toStringList()); process.start(binary.toString(), QStringList(QLatin1String("-query")), QIODevice::ReadOnly); if (!process.waitForStarted()) { *error = QCoreApplication::translate("QtVersion", "Cannot start \"%1\": %2").arg(binary.toUserOutput()).arg(process.errorString()); return QByteArray(); } if (!process.waitForFinished(timeOutMS)) { SynchronousProcess::stopProcess(process); *error = QCoreApplication::translate("QtVersion", "Timeout running \"%1\" (%2 ms).").arg(binary.toUserOutput()).arg(timeOutMS); return QByteArray(); } if (process.exitStatus() != QProcess::NormalExit) { *error = QCoreApplication::translate("QtVersion", "\"%1\" crashed.").arg(binary.toUserOutput()); return QByteArray(); } error->clear(); return process.readAllStandardOutput(); } bool BaseQtVersion::queryQMakeVariables(const FileName &binary, const Environment &env, QHash *versionInfo, QString *error) { QString tmp; if (!error) error = &tmp; const QFileInfo qmake = binary.toFileInfo(); if (!qmake.exists() || !qmake.isExecutable() || qmake.isDir()) { *error = QCoreApplication::translate("QtVersion", "qmake \"%1\" is not an executable.").arg(binary.toUserOutput()); return false; } QByteArray output; output = runQmakeQuery(binary, env, error); if (output.isNull() && !error->isEmpty()) { // Note: Don't rerun if we were able to execute the binary before. // Try running qmake with all kinds of tool chains set up in the environment. // This is required to make non-static qmakes work on windows where every tool chain // tries to be incompatible with any other. QList abiList = Abi::abisOfBinary(binary); QList tcList = ToolChainManager::toolChains(); foreach (ToolChain *tc, tcList) { if (!abiList.contains(tc->targetAbi())) continue; Environment realEnv = env; tc->addToEnvironment(realEnv); output = runQmakeQuery(binary, realEnv, error); if (error->isEmpty()) break; } } if (output.isNull()) return false; QTextStream stream(&output); while (!stream.atEnd()) { const QString line = stream.readLine(); const int index = line.indexOf(QLatin1Char(':')); if (index != -1) { QString name = line.left(index); QString value = QDir::fromNativeSeparators(line.mid(index+1)); if (value.isNull()) value = QLatin1String(""); // Make sure it is not null, to discern from missing keys versionInfo->insert(name, value); if (name.startsWith(QLatin1String("QT_")) && !name.contains(QLatin1Char('/'))) { if (name.startsWith(QLatin1String("QT_INSTALL_"))) { versionInfo->insert(name + QLatin1String("/raw"), value); versionInfo->insert(name + QLatin1String("/get"), value); if (name == QLatin1String("QT_INSTALL_PREFIX") || name == QLatin1String("QT_INSTALL_DATA") || name == QLatin1String("QT_INSTALL_BINS")) { name.replace(3, 7, QLatin1String("HOST")); versionInfo->insert(name, value); versionInfo->insert(name + QLatin1String("/get"), value); } } else if (name.startsWith(QLatin1String("QT_HOST_"))) { versionInfo->insert(name + QLatin1String("/get"), value); } } } } return true; } FileName BaseQtVersion::mkspecDirectoryFromVersionInfo(const QHash &versionInfo) { QString dataDir = qmakeProperty(versionInfo, "QT_HOST_DATA", PropertyVariantSrc); if (dataDir.isEmpty()) return FileName(); return FileName::fromUserInput(dataDir + QLatin1String("/mkspecs")); } FileName BaseQtVersion::mkspecFromVersionInfo(const QHash &versionInfo) { FileName baseMkspecDir = mkspecDirectoryFromVersionInfo(versionInfo); if (baseMkspecDir.isEmpty()) return FileName(); bool qt5 = false; QString theSpec = qmakeProperty(versionInfo, "QMAKE_XSPEC"); if (theSpec.isEmpty()) theSpec = QLatin1String("default"); else qt5 = true; FileName mkspecFullPath = baseMkspecDir; mkspecFullPath.appendPath(theSpec); // qDebug() << "default mkspec is located at" << mkspecFullPath; if (HostOsInfo::isWindowsHost()) { if (!qt5) { QFile f2(mkspecFullPath.toString() + QLatin1String("/qmake.conf")); if (f2.exists() && f2.open(QIODevice::ReadOnly)) { while (!f2.atEnd()) { QByteArray line = f2.readLine(); if (line.startsWith("QMAKESPEC_ORIGINAL")) { const QList &temp = line.split('='); if (temp.size() == 2) { QString possibleFullPath = QString::fromLocal8Bit(temp.at(1).trimmed().constData()); if (possibleFullPath.contains(QLatin1Char('$'))) { // QTBUG-28792 const QRegExp rex(QLatin1String("\\binclude\\(([^)]+)/qmake\\.conf\\)")); if (rex.indexIn(QString::fromLocal8Bit(f2.readAll())) != -1) { possibleFullPath = mkspecFullPath.toString() + QLatin1Char('/') + rex.cap(1); } } // We sometimes get a mix of different slash styles here... possibleFullPath = possibleFullPath.replace(QLatin1Char('\\'), QLatin1Char('/')); if (QFileInfo::exists(possibleFullPath)) // Only if the path exists mkspecFullPath = FileName::fromUserInput(possibleFullPath); } break; } } f2.close(); } } } else { if (HostOsInfo::isMacHost()) { QFile f2(mkspecFullPath.toString() + QLatin1String("/qmake.conf")); if (f2.exists() && f2.open(QIODevice::ReadOnly)) { while (!f2.atEnd()) { QByteArray line = f2.readLine(); if (line.startsWith("MAKEFILE_GENERATOR")) { const QList &temp = line.split('='); if (temp.size() == 2) { const QByteArray &value = temp.at(1); if (value.contains("XCODE")) { // we don't want to generate xcode projects... // qDebug() << "default mkspec is xcode, falling back to g++"; return baseMkspecDir.appendPath(QLatin1String("macx-g++")); } } break; } } f2.close(); } } if (!qt5) { //resolve mkspec link QString rspec = mkspecFullPath.toFileInfo().readLink(); if (!rspec.isEmpty()) mkspecFullPath = FileName::fromUserInput( QDir(baseMkspecDir.toString()).absoluteFilePath(rspec)); } } return mkspecFullPath; } FileName BaseQtVersion::sourcePath(const QHash &versionInfo) { const QString qt5Source = qmakeProperty(versionInfo, "QT_INSTALL_PREFIX/src"); if (!qt5Source.isEmpty()) return Utils::FileName::fromString(qt5Source); const QString installData = qmakeProperty(versionInfo, "QT_INSTALL_PREFIX"); QString sourcePath = installData; QFile qmakeCache(installData + QLatin1String("/.qmake.cache")); if (qmakeCache.exists()) { qmakeCache.open(QIODevice::ReadOnly | QIODevice::Text); QTextStream stream(&qmakeCache); while (!stream.atEnd()) { QString line = stream.readLine().trimmed(); if (line.startsWith(QLatin1String("QT_SOURCE_TREE"))) { sourcePath = line.split(QLatin1Char('=')).at(1).trimmed(); if (sourcePath.startsWith(QLatin1String("$$quote("))) { sourcePath.remove(0, 8); sourcePath.chop(1); } break; } } } return FileName::fromUserInput(sourcePath); } bool BaseQtVersion::isSubProject(const Utils::FileName &filePath) { const Utils::FileName &source = sourcePath(); if (!source.isEmpty()) { QDir dir = QDir(source.toString()); if (dir.dirName() == QLatin1String("qtbase")) dir.cdUp(); if (filePath.isChildOf(dir)) return true; } const QString &examples = examplesPath(); if (!examples.isEmpty() && filePath.isChildOf(QDir(examples))) return true; const QString &demos = demosPath(); if (!demos.isEmpty() && filePath.isChildOf(QDir(demos))) return true; return false; } bool BaseQtVersion::isQmlDebuggingSupported(Kit *k, QString *reason) { QTC_ASSERT(k, return false); BaseQtVersion *version = QtKitInformation::qtVersion(k); if (!version) { if (reason) *reason = QCoreApplication::translate("BaseQtVersion", "No Qt version."); return false; } return version->isQmlDebuggingSupported(reason); } bool BaseQtVersion::isQmlDebuggingSupported(QString *reason) const { if (!isValid()) { if (reason) *reason = QCoreApplication::translate("BaseQtVersion", "Invalid Qt version."); return false; } if (qtVersion() < QtVersionNumber(4, 8, 0)) { if (reason) *reason = QCoreApplication::translate("BaseQtVersion", "Requires Qt 4.8.0 or newer."); return false; } return true; } bool BaseQtVersion::isQtQuickCompilerSupported(Kit *k, QString *reason) { QTC_ASSERT(k, return false); BaseQtVersion *version = QtKitInformation::qtVersion(k); if (!version) { if (reason) *reason = QCoreApplication::translate("BaseQtVersion", "No Qt version."); return false; } return version->isQtQuickCompilerSupported(reason); } bool BaseQtVersion::isQtQuickCompilerSupported(QString *reason) const { if (!isValid()) { if (reason) *reason = QCoreApplication::translate("BaseQtVersion", "Invalid Qt version."); return false; } if (qtVersion() < QtVersionNumber(5, 3, 0)) { if (reason) *reason = QCoreApplication::translate("BaseQtVersion", "Requires Qt 5.3.0 or newer."); return false; } const QString qtQuickCompilerExecutable = HostOsInfo::withExecutableSuffix(binPath().toString() + QLatin1String("/qtquickcompiler")); if (!QFileInfo::exists(qtQuickCompilerExecutable)) { // TODO: Add reason string in master return false; } return true; } void BaseQtVersion::buildDebuggingHelper(Kit *k, int tools) { BaseQtVersion *version = QtKitInformation::qtVersion(k); ToolChain *tc = ToolChainKitInformation::toolChain(k); if (!k || !version || !tc) return; version->buildDebuggingHelper(tc, tools); } void BaseQtVersion::buildDebuggingHelper(ToolChain *tc, int tools) { QTC_ASSERT(tc, return); DebuggingHelperBuildTask *buildTask = new DebuggingHelperBuildTask(this, tc, static_cast(tools)); // pop up Application Output on error buildTask->showOutputOnError(true); QFuture task = QtConcurrent::run(&QtSupport::DebuggingHelperBuildTask::run, buildTask); const QString taskName = QCoreApplication::translate("BaseQtVersion", "Building Debugging Helpers"); ProgressManager::addTask(task, taskName, "Qt::BuildHelpers"); } QList BaseQtVersion::qtCorePaths(const QHash &versionInfo, const QString &versionString) { QStringList dirs; dirs << qmakeProperty(versionInfo, "QT_INSTALL_LIBS") << qmakeProperty(versionInfo, "QT_INSTALL_BINS"); QList staticLibs; QList dynamicLibs; foreach (const QString &dir, dirs) { if (dir.isEmpty()) continue; QDir d(dir); QFileInfoList infoList = d.entryInfoList(); foreach (const QFileInfo &info, infoList) { const QString file = info.fileName(); if (info.isDir() && file.startsWith(QLatin1String("QtCore")) && file.endsWith(QLatin1String(".framework"))) { // handle Framework FileName lib(info); dynamicLibs.append(lib.appendPath(file.left(file.lastIndexOf(QLatin1Char('.'))))); } else if (info.isReadable()) { if (file.startsWith(QLatin1String("libQtCore")) || file.startsWith(QLatin1String("libQt5Core")) || file.startsWith(QLatin1String("QtCore")) || file.startsWith(QLatin1String("Qt5Core"))) { if (file.endsWith(QLatin1String(".a")) || file.endsWith(QLatin1String(".lib"))) staticLibs.append(FileName(info)); else if (file.endsWith(QLatin1String(".dll")) || file.endsWith(QString::fromLatin1(".so.") + versionString) || file.endsWith(QLatin1String(".so")) || file.endsWith(QLatin1Char('.') + versionString + QLatin1String(".dylib"))) dynamicLibs.append(FileName(info)); } } } } // Only handle static libs if we can not find dynamic ones: if (dynamicLibs.isEmpty()) return staticLibs; return dynamicLibs; } QList BaseQtVersion::qtAbisFromLibrary(const QList &coreLibraries) { QList res; foreach (const FileName &library, coreLibraries) foreach (const Abi &abi, Abi::abisOfBinary(library)) if (!res.contains(abi)) res.append(abi); return res; }