/************************************************************************** ** ** This file is part of Qt Creator ** ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). ** ** Contact: Nokia Corporation (info@qt.nokia.com) ** ** ** GNU Lesser General Public License Usage ** ** This file may be used under the terms of the GNU Lesser General Public ** License version 2.1 as published by the Free Software Foundation and ** appearing in the file LICENSE.LGPL included in the packaging of this file. ** Please review the following information to ensure the GNU Lesser General ** Public License version 2.1 requirements will be met: ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** Other Usage ** ** Alternatively, this file may be used in accordance with the terms and ** conditions contained in a signed written agreement between you and Nokia. ** ** If you have questions regarding the use of this file, please contact ** Nokia at qt-info@nokia.com. ** **************************************************************************/ #include "qtversionmanager.h" #include "qt4projectmanagerconstants.h" #include "qt4target.h" #include "profilereader.h" #include "qt-maemo/maemoglobal.h" #include "qt-maemo/maemomanager.h" #include "qt-s60/s60manager.h" #include "qt-s60/abldparser.h" #include "qt-s60/sbsv2parser.h" #include "qt-s60/gccetoolchain.h" #include "qt-s60/winscwtoolchain.h" #include "qt4basetargetfactory.h" #include "qmlobservertool.h" #include "qmldumptool.h" #include "qmldebugginglibrary.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef Q_OS_WIN # include #endif #include #include #include #include #include #include #include #include #include #include using namespace Qt4ProjectManager; using namespace Qt4ProjectManager::Internal; using ProjectExplorer::DebuggingHelperLibrary; static const char *QtVersionsSectionName = "QtVersions"; static const char *newQtVersionsKey = "NewQtVersions"; static const char *PATH_AUTODETECTION_SOURCE = "PATH"; enum { debug = 0 }; template static T *createToolChain(const QString &id) { QList factories = ExtensionSystem::PluginManager::instance()->getObjects(); foreach (ProjectExplorer::ToolChainFactory *f, factories) { if (f->id() == id) { Q_ASSERT(f->canCreate()); return static_cast(f->create()); } } return 0; } // prefer newer qts otherwise compare on id bool qtVersionNumberCompare(QtVersion *a, QtVersion *b) { return a->qtVersion() > b->qtVersion() || (a->qtVersion() == b->qtVersion() && a->uniqueId() < b->uniqueId()); } // -------------------------------------------------------------------------- // QtVersionManager // -------------------------------------------------------------------------- QtVersionManager *QtVersionManager::m_self = 0; QtVersionManager::QtVersionManager() : m_emptyVersion(new QtVersion) { m_self = this; QSettings *s = Core::ICore::instance()->settings(); m_idcount = 1; int size = s->beginReadArray(QtVersionsSectionName); for (int i = 0; i < size; ++i) { s->setArrayIndex(i); // Find the right id // Either something saved or something generated // Note: This code assumes that either all ids are read from the settings // or generated on the fly. int id = s->value("Id", -1).toInt(); if (id == -1) id = getUniqueId(); else if (m_idcount < id) m_idcount = id + 1; bool isAutodetected; QString autodetectionSource; if (s->contains("isAutodetected")) { isAutodetected = s->value("isAutodetected", false).toBool(); autodetectionSource = s->value("autodetectionSource", QString()).toString(); } else {// compatibility isAutodetected = s->value("IsSystemVersion", false).toBool(); if (isAutodetected) autodetectionSource = QLatin1String(PATH_AUTODETECTION_SOURCE); } QString qmakePath = s->value("QMakePath").toString(); if (qmakePath.isEmpty()) { QString path = s->value("Path").toString(); if (!path.isEmpty()) { foreach(const QString& command, ProjectExplorer::DebuggingHelperLibrary::possibleQMakeCommands()) { QFileInfo fi(path + "/bin/" + command); if (fi.exists()) { qmakePath = fi.filePath(); break; } } } } QtVersion *version = new QtVersion(s->value("Name").toString(), qmakePath, id, isAutodetected, autodetectionSource); // Make sure we do not import non-native separators from old Qt Creator versions: version->setSystemRoot(QDir::fromNativeSeparators(s->value("S60SDKDirectory").toString())); version->setSbsV2Directory(QDir::fromNativeSeparators(s->value(QLatin1String("SBSv2Directory")).toString())); // Update from pre-2.2: const QString mingwDir = s->value(QLatin1String("MingwDirectory")).toString(); if (!mingwDir.isEmpty()) { QFileInfo fi(mingwDir + QLatin1String("/bin/g++.exe")); if (fi.exists() && fi.isExecutable()) { ProjectExplorer::MingwToolChain *tc = createToolChain(ProjectExplorer::Constants::MINGW_TOOLCHAIN_ID); if (tc) { tc->setCompilerPath(fi.absoluteFilePath()); tc->setDisplayName(tr("MinGW from %1").arg(version->displayName())); // The debugger is set later in the autoDetect method of the MinGw tool chain factory // as the default debuggers are not yet registered. ProjectExplorer::ToolChainManager::instance()->registerToolChain(tc); } } } const QString mwcDir = s->value(QLatin1String("MwcDirectory")).toString(); if (!mwcDir.isEmpty()) m_pendingMwcUpdates.append(mwcDir); const QString gcceDir = s->value(QLatin1String("GcceDirectory")).toString(); if (!gcceDir.isEmpty()) m_pendingGcceUpdates.append(gcceDir); m_versions.insert(version->uniqueId(), version); } s->endArray(); ++m_idcount; addNewVersionsFromInstaller(); updateSystemVersion(); // cannot call from ctor, needs to get connected extenernally first QTimer::singleShot(0, this, SLOT(updateSettings())); } QtVersionManager::~QtVersionManager() { qDeleteAll(m_versions); m_versions.clear(); delete m_emptyVersion; m_emptyVersion = 0; } QtVersionManager *QtVersionManager::instance() { return m_self; } void QtVersionManager::addVersion(QtVersion *version) { QTC_ASSERT(version != 0, return); if (m_versions.contains(version->uniqueId())) return; int uniqueId = version->uniqueId(); m_versions.insert(uniqueId, version); emit qtVersionsChanged(QList() << uniqueId); writeVersionsIntoSettings(); } void QtVersionManager::removeVersion(QtVersion *version) { QTC_ASSERT(version != 0, return); m_versions.remove(version->uniqueId()); emit qtVersionsChanged(QList() << version->uniqueId()); writeVersionsIntoSettings(); delete version; } bool QtVersionManager::supportsTargetId(const QString &id) const { QList versions = QtVersionManager::instance()->versionsForTargetId(id); foreach (QtVersion *v, versions) if (v->isValid() && v->toolChainAvailable(id)) return true; return false; } QList QtVersionManager::versionsForTargetId(const QString &id, const QtVersionNumber &minimumQtVersion) const { QList targetVersions; foreach (QtVersion *version, m_versions) { if (version->supportsTargetId(id) && version->qtVersion() >= minimumQtVersion) targetVersions.append(version); } qSort(targetVersions.begin(), targetVersions.end(), &qtVersionNumberCompare); return targetVersions; } QSet QtVersionManager::supportedTargetIds() const { QSet results; foreach (QtVersion *version, m_versions) results.unite(version->supportedTargetIds()); return results; } void QtVersionManager::updateDocumentation() { Core::HelpManager *helpManager = Core::HelpManager::instance(); Q_ASSERT(helpManager); QStringList files; foreach (QtVersion *version, m_versions) { const QString docPath = version->documentationPath() + QLatin1String("/qch/"); const QDir versionHelpDir(docPath); foreach (const QString &helpFile, versionHelpDir.entryList(QStringList() << QLatin1String("*.qch"), QDir::Files)) files << docPath + helpFile; } helpManager->registerDocumentation(files); } void QtVersionManager::updateSettings() { writeVersionsIntoSettings(); updateDocumentation(); QtVersion *version = 0; QList candidates; // try to find a version which has both, demos and examples foreach (version, m_versions) { if (version->hasExamples() && version->hasDemos()) candidates.append(version); } // in SDKs, we want to prefer the Qt version shipping with the SDK QSettings *settings = Core::ICore::instance()->settings(); QString preferred = settings->value(QLatin1String("PreferredQMakePath")).toString(); preferred = QDir::fromNativeSeparators(preferred); if (!preferred.isEmpty()) { #ifdef Q_OS_WIN preferred = preferred.toLower(); if (!preferred.endsWith(QLatin1String(".exe"))) preferred.append(QLatin1String(".exe")); #endif foreach (version, candidates) { if (version->qmakeCommand() == preferred) { emit updateExamples(version->examplesPath(), version->demosPath(), version->sourcePath()); return; } } } // prefer versions with declarative examples foreach (version, candidates) { if (QDir(version->examplesPath()+"/declarative").exists()) { emit updateExamples(version->examplesPath(), version->demosPath(), version->sourcePath()); return; } } if (!candidates.isEmpty()) { version = candidates.first(); emit updateExamples(version->examplesPath(), version->demosPath(), version->sourcePath()); return; } return; } int QtVersionManager::getUniqueId() { return m_idcount++; } void QtVersionManager::writeVersionsIntoSettings() { QSettings *s = Core::ICore::instance()->settings(); s->beginWriteArray(QtVersionsSectionName); QMap::const_iterator it = m_versions.constBegin(); for (int i = 0; i < m_versions.size(); ++i) { const QtVersion *version = it.value(); s->setArrayIndex(i); s->setValue("Name", version->displayName()); // for downwards compat s->setValue("Path", version->versionInfo().value("QT_INSTALL_DATA")); s->setValue("QMakePath", version->qmakeCommand()); s->setValue("Id", version->uniqueId()); s->setValue("isAutodetected", version->isAutodetected()); if (version->isAutodetected()) s->setValue("autodetectionSource", version->autodetectionSource()); s->setValue("S60SDKDirectory", version->systemRoot()); s->setValue(QLatin1String("SBSv2Directory"), version->sbsV2Directory()); // Remove obsolete settings: New tool chains would be created at each startup // otherwise, overriding manually set ones. s->remove(QLatin1String("MingwDirectory")); s->remove(QLatin1String("MwcDirectory")); s->remove(QLatin1String("GcceDirectory")); ++it; } s->endArray(); } QList QtVersionManager::versions() const { QList versions; foreach (QtVersion *version, m_versions) versions << version; qSort(versions.begin(), versions.end(), &qtVersionNumberCompare); return versions; } QList QtVersionManager::validVersions() const { QList results; foreach(QtVersion *v, m_versions) { if (v->isValid()) results.append(v); } qSort(results.begin(), results.end(), &qtVersionNumberCompare); return results; } bool QtVersionManager::isValidId(int id) const { return m_versions.contains(id); } QString QtVersionManager::popPendingMwcUpdate() { if (m_pendingMwcUpdates.isEmpty()) return QString(); return m_pendingMwcUpdates.takeFirst(); } QString QtVersionManager::popPendingGcceUpdate() { if (m_pendingGcceUpdates.isEmpty()) return QString(); return m_pendingGcceUpdates.takeFirst(); } QtVersion *QtVersionManager::version(int id) const { QMap::const_iterator it = m_versions.find(id); if (it == m_versions.constEnd()) return m_emptyVersion; return it.value(); } // FIXME: Rework this! void QtVersionManager::addNewVersionsFromInstaller() { // Add new versions which may have been installed by the WB installer in the form: // NewQtVersions="qt 4.3.2=c:\\qt\\qt432\bin\qmake.exe;qt embedded=c:\\qtembedded;" // or NewQtVersions="qt 4.3.2=c:\\qt\\qt432bin\qmake.exe; // i.e. // NewQtVersions="versionname=pathtoversion=s60sdk;" // Duplicate entries are not added, the first new version is set as default. QSettings *settings = Core::ICore::instance()->settings(); QSettings *globalSettings = Core::ICore::instance()->settings(QSettings::SystemScope); QDateTime lastUpdateFromGlobalSettings = globalSettings->value( QLatin1String("General/LastQtVersionUpdate")).toDateTime(); const QFileInfo gsFi(globalSettings->fileName()); if ( !lastUpdateFromGlobalSettings.isNull() && (!gsFi.exists() || (gsFi.lastModified() > lastUpdateFromGlobalSettings)) ) return; if (!globalSettings->contains(newQtVersionsKey) && !globalSettings->contains(QLatin1String("Installer/")+newQtVersionsKey)) { return; } QString newVersionsValue = settings->value(newQtVersionsKey).toString(); if (newVersionsValue.isEmpty()) newVersionsValue = settings->value(QLatin1String("Installer/")+newQtVersionsKey).toString(); QStringList newVersionsList = newVersionsValue.split(';', QString::SkipEmptyParts); foreach (const QString &newVersion, newVersionsList) { QStringList newVersionData = newVersion.split('='); if (newVersionData.count() >= 2) { if (QFile::exists(newVersionData[1])) { QtVersion *version = new QtVersion(newVersionData[0], newVersionData[1], m_idcount++ ); if (newVersionData.count() >= 3) version->setSystemRoot(QDir::fromNativeSeparators(newVersionData[2])); if (newVersionData.count() >= 4) version->setSbsV2Directory(QDir::fromNativeSeparators(newVersionData[3])); bool versionWasAlreadyInList = false; foreach(const QtVersion * const it, m_versions) { if (QDir(version->qmakeCommand()).canonicalPath() == QDir(it->qmakeCommand()).canonicalPath()) { versionWasAlreadyInList = true; break; } } if (!versionWasAlreadyInList) { m_versions.insert(version->uniqueId(), version); } else { // clean up delete version; } } } } settings->setValue(QLatin1String("General/LastQtVersionUpdate"), QDateTime::currentDateTime()); } void QtVersionManager::updateSystemVersion() { bool haveSystemVersion = false; QString systemQMakePath = DebuggingHelperLibrary::findSystemQt(Utils::Environment::systemEnvironment()); if (systemQMakePath.isNull()) systemQMakePath = tr(""); foreach (QtVersion *version, m_versions) { if (version->isAutodetected() && version->autodetectionSource() == PATH_AUTODETECTION_SOURCE) { version->setQMakeCommand(systemQMakePath); version->setDisplayName(tr("Qt in PATH")); haveSystemVersion = true; } } if (haveSystemVersion) return; QtVersion *version = new QtVersion(tr("Qt in PATH"), systemQMakePath, getUniqueId(), true, PATH_AUTODETECTION_SOURCE); m_versions.insert(version->uniqueId(), version); } QtVersion *QtVersionManager::emptyVersion() const { return m_emptyVersion; } class SortByUniqueId { public: bool operator()(QtVersion *a, QtVersion *b) { return a->uniqueId() < b->uniqueId(); } }; bool QtVersionManager::equals(QtVersion *a, QtVersion *b) { if (a->m_qmakeCommand != b->m_qmakeCommand) return false; if (a->m_id != b->m_id) return false; if (a->m_displayName != b->displayName()) return false; if (a->m_sbsV2Directory != b->m_sbsV2Directory) return false; if (a->m_systemRoot != b->m_systemRoot) return false; return true; } void QtVersionManager::setNewQtVersions(QList newVersions) { // We want to preserve the same order as in the settings dialog // so we sort a copy QList sortedNewVersions = newVersions; SortByUniqueId sortByUniqueId; qSort(sortedNewVersions.begin(), sortedNewVersions.end(), sortByUniqueId); QList changedVersions; // So we trying to find the minimal set of changed versions, // iterate over both sorted list // newVersions and oldVersions iterator QList::const_iterator nit, nend; QMap::const_iterator oit, oend; nit = sortedNewVersions.constBegin(); nend = sortedNewVersions.constEnd(); oit = m_versions.constBegin(); oend = m_versions.constEnd(); while (nit != nend && oit != oend) { int nid = (*nit)->uniqueId(); int oid = (*oit)->uniqueId(); if (nid < oid) { changedVersions.push_back(nid); ++nit; } else if (oid < nid) { changedVersions.push_back(oid); ++oit; } else { if (!equals(*oit, *nit)) changedVersions.push_back(oid); ++oit; ++nit; } } while (nit != nend) { changedVersions.push_back((*nit)->uniqueId()); ++nit; } while (oit != oend) { changedVersions.push_back((*oit)->uniqueId()); ++oit; } qDeleteAll(m_versions); m_versions.clear(); foreach (QtVersion *v, sortedNewVersions) m_versions.insert(v->uniqueId(), v); if (!changedVersions.isEmpty()) updateDocumentation(); updateSettings(); writeVersionsIntoSettings(); if (!changedVersions.isEmpty()) emit qtVersionsChanged(changedVersions); } // -------------------------------------------------------------------------- // QtVersion // -------------------------------------------------------------------------- QtVersion::QtVersion(const QString &name, const QString &qmakeCommand, int id, bool isAutodetected, const QString &autodetectionSource) : m_displayName(name), m_isAutodetected(isAutodetected), m_autodetectionSource(autodetectionSource), m_hasDebuggingHelper(false), m_hasQmlDump(false), m_hasQmlDebuggingLibrary(false), m_hasQmlObserver(false), m_abiUpToDate(false), m_versionInfoUpToDate(false), m_notInstalled(false), m_defaultConfigIsDebug(true), m_defaultConfigIsDebugAndRelease(true), m_hasExamples(false), m_hasDemos(false), m_hasDocumentation(false), m_qmakeIsExecutable(false), m_validSystemRoot(true) { if (id == -1) m_id = getUniqueId(); else m_id = id; setQMakeCommand(qmakeCommand); } QtVersion::QtVersion(const QString &name, const QString &qmakeCommand, bool isAutodetected, const QString &autodetectionSource) : m_displayName(name), m_isAutodetected(isAutodetected), m_autodetectionSource(autodetectionSource), m_hasDebuggingHelper(false), m_hasQmlDump(false), m_hasQmlDebuggingLibrary(false), m_hasQmlObserver(false), m_abiUpToDate(false), m_versionInfoUpToDate(false), m_notInstalled(false), m_defaultConfigIsDebug(true), m_defaultConfigIsDebugAndRelease(true), m_hasExamples(false), m_hasDemos(false), m_hasDocumentation(false), m_qmakeIsExecutable(false), m_validSystemRoot(true) { m_id = getUniqueId(); setQMakeCommand(qmakeCommand); } QtVersion::QtVersion(const QString &qmakeCommand, bool isAutodetected, const QString &autodetectionSource) : m_isAutodetected(isAutodetected), m_autodetectionSource(autodetectionSource), m_hasDebuggingHelper(false), m_hasQmlDump(false), m_hasQmlDebuggingLibrary(false), m_hasQmlObserver(false), m_abiUpToDate(false), m_versionInfoUpToDate(false), m_notInstalled(false), m_defaultConfigIsDebug(true), m_defaultConfigIsDebugAndRelease(true), m_hasExamples(false), m_hasDemos(false), m_hasDocumentation(false), m_qmakeIsExecutable(false), m_validSystemRoot(true) { m_id = getUniqueId(); setQMakeCommand(qmakeCommand); m_displayName = qtVersionString(); } QtVersion::QtVersion() : m_id(-1), m_isAutodetected(false), m_hasDebuggingHelper(false), m_hasQmlDump(false), m_hasQmlDebuggingLibrary(false), m_hasQmlObserver(false), m_abiUpToDate(false), m_versionInfoUpToDate(false), m_notInstalled(false), m_defaultConfigIsDebug(true), m_defaultConfigIsDebugAndRelease(true), m_hasExamples(false), m_hasDemos(false), m_hasDocumentation(false) , m_qmakeIsExecutable(false), m_validSystemRoot(true) { setQMakeCommand(QString()); } QtVersion::~QtVersion() { } QString QtVersion::toHtml(bool verbose) const { QString rc; QTextStream str(&rc); str << ""; str << ""; if (!isValid()) { str << ""; } else { QString prefix = QLatin1String(""); foreach (const ProjectExplorer::Abi &abi, qtAbis()) { str << prefix << ""; prefix = QLatin1String(""); } str << ""; str << ""; str << ""; updateAbiAndMkspec(); if (m_defaultConfigIsDebug || m_defaultConfigIsDebugAndRelease) { str << ""; } // default config. str << ""; if (verbose) { const QHash vInfo = versionInfo(); if (!vInfo.isEmpty()) { const QHash::const_iterator vcend = vInfo.constEnd(); for (QHash::const_iterator it = vInfo.constBegin(); it != vcend; ++it) str << ""; } } } str << "
" << QtVersionManager::tr("Name:") << "" << displayName() << "
" + QtVersionManager::tr("Invalid Qt version") +"
") + QtVersionManager::tr("ABI:") + QLatin1String("" << abi.toString() << "
" << QtVersionManager::tr("Source:") << "" << sourcePath() << "
" << QtVersionManager::tr("mkspec:") << "" << mkspec() << "
" << QtVersionManager::tr("qmake:") << "" << m_qmakeCommand << "
" << QtVersionManager::tr("Default:") << "" << (m_defaultConfigIsDebug ? "debug" : "release"); if (m_defaultConfigIsDebugAndRelease) str << " debug_and_release"; str << "
" << QtVersionManager::tr("Version:") << "" << qtVersionString() << "
" << it.key() <<  "
" << it.value() << "
"; return rc; } bool QtVersion::supportsShadowBuilds() const { QSet targets = supportedTargetIds(); // Symbian does not support shadow building if (targets.contains(Constants::S60_DEVICE_TARGET_ID) || targets.contains(Constants::S60_EMULATOR_TARGET_ID)) { // We can not support shadow building with the ABLD system return false; } #ifdef Q_OS_WIN if (targets.contains(Constants::MEEGO_DEVICE_TARGET_ID) || targets.contains(Constants::MAEMO5_DEVICE_TARGET_ID) || targets.contains(Constants::HARMATTAN_DEVICE_TARGET_ID)) return false; #endif return true; } ProjectExplorer::IOutputParser *QtVersion::createOutputParser() const { if (supportsTargetId(Qt4ProjectManager::Constants::S60_DEVICE_TARGET_ID) || supportsTargetId(Qt4ProjectManager::Constants::S60_EMULATOR_TARGET_ID)) { if (isBuildWithSymbianSbsV2()) { return new SbsV2Parser; } else { ProjectExplorer::IOutputParser *parser = new AbldParser; parser->appendOutputParser(new ProjectExplorer::GnuMakeParser); return parser; } } return new ProjectExplorer::GnuMakeParser; } QList QtVersion::reportIssues(const QString &proFile, const QString &buildDir, bool includeTargetSpecificErrors) { 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("Qt4ProjectManager::QtVersion", "The Qt version is invalid: %1").arg(invalidReason()); results.append(ProjectExplorer::Task(ProjectExplorer::Task::Error, msg, QString(), -1, QLatin1String(ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM))); } QFileInfo qmakeInfo(qmakeCommand()); if (!qmakeInfo.exists() || !qmakeInfo.isExecutable()) { //: %1: Path to qmake executable const QString msg = QCoreApplication::translate("Qt4ProjectManager::QtVersion", "The qmake command \"%1\" was not found or is not executable.").arg(qmakeCommand()); results.append(ProjectExplorer::Task(ProjectExplorer::Task::Error, msg, QString(), -1, QLatin1String(ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM))); } QString sourcePath = QFileInfo(proFile).absolutePath(); if (!sourcePath.endsWith(QLatin1Char('/'))) sourcePath.append(QLatin1Char('/')); if ((tmpBuildDir.startsWith(sourcePath)) && (tmpBuildDir != sourcePath)) { const QString msg = QCoreApplication::translate("Qt4ProjectManager::QtVersion", "Qmake does not support build directories below the source directory."); results.append(ProjectExplorer::Task(ProjectExplorer::Task::Warning, msg, QString(), -1, QLatin1String(ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM))); } else if (tmpBuildDir.count(QChar('/')) != sourcePath.count(QChar('/'))) { const QString msg = QCoreApplication::translate("Qt4ProjectManager::QtVersion", "The build directory needs to be at the same level as the source directory."); results.append(ProjectExplorer::Task(ProjectExplorer::Task::Warning, msg, QString(), -1, QLatin1String(ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM))); } #if defined (Q_OS_WIN) QSet targets = supportedTargetIds(); if (targets.contains(Constants::S60_DEVICE_TARGET_ID) || targets.contains(Constants::S60_EMULATOR_TARGET_ID)) { const QString epocRootDir = systemRoot(); // Report an error if project- and epoc directory are on different drives: if (!epocRootDir.startsWith(proFile.left(3), Qt::CaseInsensitive) && !isBuildWithSymbianSbsV2()) { results.append(ProjectExplorer::Task(ProjectExplorer::Task::Error, QCoreApplication::translate("ProjectExplorer::Internal::S60ProjectChecker", "The Symbian SDK and the project sources must reside on the same drive."), QString(), -1, ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM)); } } #endif if (includeTargetSpecificErrors) { QList factories; foreach (const QString &id, supportedTargetIds()) if (Qt4BaseTargetFactory *factory = Qt4BaseTargetFactory::qt4BaseTargetFactoryForId(id)) factories << factory; qSort(factories); QList::iterator newend = std::unique(factories.begin(), factories.end()); QList::iterator it = factories.begin(); for ( ; it != newend; ++it) results.append((*it)->reportIssues(proFile)); } return results; } QString QtVersion::displayName() const { return m_displayName; } QString QtVersion::qmakeCommand() const { return m_qmakeCommand; } QString QtVersion::sourcePath() const { return m_sourcePath; } QString QtVersion::mkspec() const { updateAbiAndMkspec(); return m_mkspec; } QString QtVersion::mkspecPath() const { updateAbiAndMkspec(); return m_mkspecFullPath; } bool QtVersion::isBuildWithSymbianSbsV2() const { updateAbiAndMkspec(); return m_isBuildUsingSbsV2; } QString QtVersion::qtVersionString() const { if (m_qtVersionString.isNull()) { QFileInfo qmake(m_qmakeCommand); if (qmake.exists() && qmake.isExecutable()) { m_qtVersionString = DebuggingHelperLibrary::qtVersionForQMake(qmake.absoluteFilePath()); } else { m_qtVersionString = QLatin1String(""); } } return m_qtVersionString; } QtVersionNumber QtVersion::qtVersion() const { //todo cache this; return QtVersionNumber(qtVersionString()); } QHash QtVersion::versionInfo() const { updateVersionInfo(); return m_versionInfo; } void QtVersion::setDisplayName(const QString &name) { m_displayName = name; } void QtVersion::setQMakeCommand(const QString& qmakeCommand) { m_qmakeCommand = QDir::fromNativeSeparators(qmakeCommand); #ifdef Q_OS_WIN m_qmakeCommand = m_qmakeCommand.toLower(); #endif m_designerCommand.clear(); m_linguistCommand.clear(); m_qmlviewerCommand.clear(); m_uicCommand.clear(); m_abiUpToDate = false; // TODO do i need to optimize this? m_versionInfoUpToDate = false; m_qtVersionString.clear(); updateSourcePath(); } void QtVersion::updateSourcePath() { updateVersionInfo(); const QString installData = m_versionInfo["QT_INSTALL_DATA"]; m_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"))) { m_sourcePath = line.split(QLatin1Char('=')).at(1).trimmed(); if (m_sourcePath.startsWith(QLatin1String("$$quote("))) { m_sourcePath.remove(0, 8); m_sourcePath.chop(1); } break; } } } m_sourcePath = QDir::cleanPath(m_sourcePath); #ifdef Q_OS_WIN m_sourcePath = m_sourcePath.toLower(); #endif } // Returns the version that was used to build the project in that directory // That is returns the directory // To find out whether we already have a qtversion for that directory call // QtVersion *QtVersionManager::qtVersionForDirectory(const QString directory); QString QtVersionManager::findQMakeBinaryFromMakefile(const QString &makefile) { bool debugAdding = false; QFile fi(makefile); if (fi.exists() && fi.open(QFile::ReadOnly)) { QTextStream ts(&fi); QRegExp r1("QMAKE\\s*=(.*)"); while (!ts.atEnd()) { QString line = ts.readLine(); if (r1.exactMatch(line)) { if (debugAdding) qDebug()<<"#~~ QMAKE is:"<qmakeCommand() == qmakePath) { return v; break; } } return 0; } void dumpQMakeAssignments(const QList &list) { foreach(const QMakeAssignment &qa, list) { qDebug()< QtVersionManager::scanMakeFile(const QString &makefile, QtVersion::QmakeBuildConfigs defaultBuildConfig) { if (debug) qDebug()<<"ScanMakeFile, the gory details:"; QtVersion::QmakeBuildConfigs result = defaultBuildConfig; QString result2; QString line = findQMakeLine(makefile, QLatin1String("# Command:")); if (!line.isEmpty()) { if (debug) qDebug()<<"Found line"< assignments; QList afterAssignments; parseArgs(line, &assignments, &afterAssignments, &result2); if (debug) { dumpQMakeAssignments(assignments); if (!afterAssignments.isEmpty()) qDebug()<<"-after"; dumpQMakeAssignments(afterAssignments); } // Search in assignments for CONFIG(+=,-=,=)(debug,release,debug_and_release) // Also remove them from the list result = qmakeBuildConfigFromCmdArgs(&assignments, defaultBuildConfig); if (debug) dumpQMakeAssignments(assignments); foreach(const QMakeAssignment &qa, assignments) Utils::QtcProcess::addArg(&result2, qa.variable + qa.op + qa.value); if (!afterAssignments.isEmpty()) { Utils::QtcProcess::addArg(&result2, QLatin1String("-after")); foreach(const QMakeAssignment &qa, afterAssignments) Utils::QtcProcess::addArg(&result2, qa.variable + qa.op + qa.value); } } // Dump the gathered information: if (debug) { qDebug()<<"\n\nDumping information from scanMakeFile"; qDebug()<<"QMake CONFIG variable parsing"; qDebug()<<" "<< (result & QtVersion::NoBuild ? "No Build" : QString::number(int(result))); qDebug()<<" "<< (result & QtVersion::DebugBuild ? "debug" : "release"); qDebug()<<" "<< (result & QtVersion::BuildAll ? "debug_and_release" : "no debug_and_release"); qDebug()<<"\nAddtional Arguments"; qDebug()< *assignments, QList *afterAssignments, QString *additionalArguments) { QRegExp regExp("([^\\s\\+-]*)\\s*(\\+=|=|-=|~=)(.*)"); bool after = false; bool ignoreNext = false; *additionalArguments = args; Utils::QtcProcess::ArgIterator ait(additionalArguments); while (ait.next()) { if (ignoreNext) { // Ignoring ignoreNext = false; ait.deleteArg(); } else if (ait.value() == QLatin1String("-after")) { after = true; ait.deleteArg(); } else if (ait.value().contains(QLatin1Char('='))) { if (regExp.exactMatch(ait.value())) { QMakeAssignment qa; qa.variable = regExp.cap(1); qa.op = regExp.cap(2); qa.value = regExp.cap(3).trimmed(); if (after) afterAssignments->append(qa); else assignments->append(qa); } else { qDebug()<<"regexp did not match"; } ait.deleteArg(); } else if (ait.value() == QLatin1String("-o")) { ignoreNext = true; ait.deleteArg(); #if defined(Q_OS_WIN32) } else if (ait.value() == QLatin1String("-win32")) { #elif defined(Q_OS_MAC) } else if (ait.value() == QLatin1String("-macx")) { #elif defined(Q_OS_QNX6) } else if (ait.value() == QLatin1String("-qnx6")) { #else } else if (ait.value() == QLatin1String("-unix")) { #endif ait.deleteArg(); } } ait.deleteArg(); // The .pro file is always the last arg } /// This function extracts all the CONFIG+=debug, CONFIG+=release QtVersion::QmakeBuildConfigs QtVersionManager::qmakeBuildConfigFromCmdArgs(QList *assignments, QtVersion::QmakeBuildConfigs defaultBuildConfig) { QtVersion::QmakeBuildConfigs result = defaultBuildConfig; QList oldAssignments = *assignments; assignments->clear(); foreach(const QMakeAssignment &qa, oldAssignments) { if (qa.variable == "CONFIG") { QStringList values = qa.value.split(' '); QStringList newValues; foreach(const QString &value, values) { if (value == "debug") { if (qa.op == "+=") result = result | QtVersion::DebugBuild; else result = result & ~QtVersion::DebugBuild; } else if (value == "release") { if (qa.op == "+=") result = result & ~QtVersion::DebugBuild; else result = result | QtVersion::DebugBuild; } else if (value == "debug_and_release") { if (qa.op == "+=") result = result | QtVersion::BuildAll; else result = result & ~QtVersion::BuildAll; } else { newValues.append(value); } QMakeAssignment newQA = qa; newQA.value = newValues.join(" "); if (!newValues.isEmpty()) assignments->append(newQA); } } else { assignments->append(qa); } } return result; } static bool queryQMakeVariables(const QString &binary, QHash *versionInfo) { const int timeOutMS = 30000; // Might be slow on some machines. QFileInfo qmake(binary); static const char * const variables[] = { "QT_VERSION", "QT_INSTALL_DATA", "QT_INSTALL_LIBS", "QT_INSTALL_HEADERS", "QT_INSTALL_DEMOS", "QT_INSTALL_EXAMPLES", "QT_INSTALL_CONFIGURATION", "QT_INSTALL_TRANSLATIONS", "QT_INSTALL_PLUGINS", "QT_INSTALL_BINS", "QT_INSTALL_DOCS", "QT_INSTALL_PREFIX", "QT_INSTALL_IMPORTS", "QMAKEFEATURES" }; QStringList args; for (uint i = 0; i < sizeof variables / sizeof variables[0]; ++i) args << "-query" << variables[i]; QProcess process; process.start(qmake.absoluteFilePath(), args, QIODevice::ReadOnly); if (!process.waitForStarted()) { qWarning("Cannot start '%s': %s", qPrintable(binary), qPrintable(process.errorString())); return false; } if (!process.waitForFinished(timeOutMS)) { Utils::SynchronousProcess::stopProcess(process); qWarning("Timeout running '%s' (%dms).", qPrintable(binary), timeOutMS); return false; } if (process.exitStatus() != QProcess::NormalExit) { qWarning("'%s' crashed.", qPrintable(binary)); return false; } QByteArray output = process.readAllStandardOutput(); QTextStream stream(&output); while (!stream.atEnd()) { const QString line = stream.readLine(); const int index = line.indexOf(QLatin1Char(':')); if (index != -1) { const QString value = QDir::fromNativeSeparators(line.mid(index+1)); if (value != "**Unknown**") versionInfo->insert(line.left(index), value); } } return true; } void QtVersion::updateVersionInfo() const { if (m_versionInfoUpToDate) return; // extract data from qmake executable m_versionInfo.clear(); m_notInstalled = false; m_hasExamples = false; m_hasDocumentation = false; m_hasDebuggingHelper = false; m_hasQmlDump = false; m_hasQmlDebuggingLibrary = false; m_hasQmlObserver = false; m_qmakeIsExecutable = true; QFileInfo fi(qmakeCommand()); if (!fi.exists() || !fi.isExecutable()) { m_qmakeIsExecutable = false; return; } if (!queryQMakeVariables(qmakeCommand(), &m_versionInfo)) return; if (m_versionInfo.contains("QT_INSTALL_DATA")) { QString qtInstallData = m_versionInfo.value("QT_INSTALL_DATA"); m_versionInfo.insert("QMAKE_MKSPECS", QDir::cleanPath(qtInstallData+"/mkspecs")); if (!qtInstallData.isEmpty()) { m_hasDebuggingHelper = !DebuggingHelperLibrary::debuggingHelperLibraryByInstallData(qtInstallData).isEmpty(); m_hasQmlDump = !QmlDumpTool::toolByInstallData(qtInstallData, false).isEmpty() || !QmlDumpTool::toolByInstallData(qtInstallData, true).isEmpty(); m_hasQmlDebuggingLibrary = !QmlDebuggingLibrary::libraryByInstallData(qtInstallData, false).isEmpty() || !QmlDebuggingLibrary::libraryByInstallData(qtInstallData, true).isEmpty(); m_hasQmlObserver = !QmlObserverTool::toolByInstallData(qtInstallData).isEmpty(); } } // Now check for a qt that is configured with a prefix but not installed if (m_versionInfo.contains("QT_INSTALL_BINS")) { QFileInfo fi(m_versionInfo.value("QT_INSTALL_BINS")); if (!fi.exists()) m_notInstalled = true; } if (m_versionInfo.contains("QT_INSTALL_HEADERS")){ QFileInfo fi(m_versionInfo.value("QT_INSTALL_HEADERS")); if (!fi.exists()) m_notInstalled = true; } if (m_versionInfo.contains("QT_INSTALL_DOCS")){ QFileInfo fi(m_versionInfo.value("QT_INSTALL_DOCS")); if (fi.exists()) m_hasDocumentation = true; } if (m_versionInfo.contains("QT_INSTALL_EXAMPLES")){ QFileInfo fi(m_versionInfo.value("QT_INSTALL_EXAMPLES")); if (fi.exists()) m_hasExamples = true; } if (m_versionInfo.contains("QT_INSTALL_DEMOS")){ QFileInfo fi(m_versionInfo.value("QT_INSTALL_DEMOS")); if (fi.exists()) m_hasDemos = true; } m_versionInfoUpToDate = true; } QString QtVersion::findQtBinary(const QStringList &possibleCommands) const { const QString qtdirbin = versionInfo().value(QLatin1String("QT_INSTALL_BINS")) + QLatin1Char('/'); foreach (const QString &possibleCommand, possibleCommands) { const QString fullPath = qtdirbin + possibleCommand; if (QFileInfo(fullPath).isFile()) return QDir::cleanPath(fullPath); } return QString(); } QString QtVersion::uicCommand() const { if (!isValid()) return QString(); if (!m_uicCommand.isNull()) return m_uicCommand; #ifdef Q_OS_WIN const QStringList possibleCommands(QLatin1String("uic.exe")); #else QStringList possibleCommands; possibleCommands << QLatin1String("uic-qt4") << QLatin1String("uic4") << QLatin1String("uic"); #endif m_uicCommand = findQtBinary(possibleCommands); return m_uicCommand; } // Return a list of GUI binary names // 'foo', 'foo.exe', 'Foo.app/Contents/MacOS/Foo' static inline QStringList possibleGuiBinaries(const QString &name) { #ifdef Q_OS_WIN return QStringList(name + QLatin1String(".exe")); #elif defined(Q_OS_MAC) // 'Foo.app/Contents/MacOS/Foo' QString upCaseName = name; upCaseName[0] = upCaseName.at(0).toUpper(); QString macBinary = upCaseName; macBinary += QLatin1String(".app/Contents/MacOS/"); macBinary += upCaseName; return QStringList(macBinary); #else return QStringList(name); #endif } QString QtVersion::designerCommand() const { if (!isValid()) return QString(); if (m_designerCommand.isNull()) m_designerCommand = findQtBinary(possibleGuiBinaries(QLatin1String("designer"))); return m_designerCommand; } QString QtVersion::linguistCommand() const { if (!isValid()) return QString(); if (m_linguistCommand.isNull()) m_linguistCommand = findQtBinary(possibleGuiBinaries(QLatin1String("linguist"))); return m_linguistCommand; } QString QtVersion::qmlviewerCommand() const { if (!isValid()) return QString(); if (m_qmlviewerCommand.isNull()) { #ifdef Q_OS_MAC const QString qmlViewerName = QLatin1String("QMLViewer"); #else const QString qmlViewerName = QLatin1String("qmlviewer"); #endif m_qmlviewerCommand = findQtBinary(possibleGuiBinaries(qmlViewerName)); } return m_qmlviewerCommand; } void QtVersion::setSystemRoot(const QString &root) { if (root == m_systemRoot) return; m_systemRoot = root; m_abiUpToDate = false; } QString QtVersion::systemRoot() const { updateAbiAndMkspec(); return m_systemRoot; } bool QtVersion::supportsTargetId(const QString &id) const { updateAbiAndMkspec(); return m_targetIds.contains(id); } QSet QtVersion::supportedTargetIds() const { updateAbiAndMkspec(); return m_targetIds; } QList QtVersion::qtAbis() const { updateAbiAndMkspec(); return m_abis; } // if none, then it's INVALID everywhere this function is called void QtVersion::updateAbiAndMkspec() const { if (m_id == -1 || m_abiUpToDate) return; m_abiUpToDate = true; m_targetIds.clear(); m_abis.clear(); m_validSystemRoot = true; // qDebug()<<"Finding mkspec for"< &temp = line.split('='); if (temp.size() == 2) { QString possibleFullPath = temp.at(1).trimmed(); // We sometimes get a mix of different slash styles here... possibleFullPath = possibleFullPath.replace('\\', '/'); if (QFileInfo(possibleFullPath).exists()) // Only if the path exists mkspecFullPath = possibleFullPath; } break; } } f2.close(); } #elif defined(Q_OS_MAC) QFile f2(mkspecFullPath + "/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++"; mkspecFullPath = baseMkspecDir + "/macx-g++"; } //resolve mkspec link mkspecFullPath = resolveLink(mkspecFullPath); } break; } } f2.close(); } #else mkspecFullPath =resolveLink(mkspecFullPath); #endif #ifdef Q_OS_WIN mkspecFullPath = mkspecFullPath.toLower(); #endif m_mkspecFullPath = mkspecFullPath; QString mkspec = m_mkspecFullPath; if (mkspec.startsWith(baseMkspecDir)) { mkspec = mkspec.mid(baseMkspecDir.length() + 1); // qDebug() << "Setting mkspec to"<incRefCount(); ProFileParser parser(ProFileCacheManager::instance()->cache(), &msgHandler); ProFileEvaluator evaluator(&option, &parser, &msgHandler); if (ProFile *pro = parser.parsedProFile(m_mkspecFullPath + "/qmake.conf")) { evaluator.setCumulative(false); evaluator.accept(pro, ProFileEvaluator::LoadProOnly); pro->deref(); } QString qmakeCXX = evaluator.values("QMAKE_CXX").join(" "); QString makefileGenerator = evaluator.value("MAKEFILE_GENERATOR"); QString ce_sdk = evaluator.values("CE_SDK").join(QLatin1String(" ")); QString ce_arch = evaluator.value("CE_ARCH"); const QString coreLibrary = qtCorePath(); // Evaluate all the information we have: if (!ce_sdk.isEmpty() && !ce_arch.isEmpty()) { // Treat windows CE as desktop. m_abis.append(ProjectExplorer::Abi(ProjectExplorer::Abi::ArmArchitecture, ProjectExplorer::Abi::WindowsOS, ProjectExplorer::Abi::WindowsCEFlavor, ProjectExplorer::Abi::PEFormat, false)); m_targetIds.insert(Constants::DESKTOP_TARGET_ID); } else if (makefileGenerator == QLatin1String("SYMBIAN_ABLD") || makefileGenerator == QLatin1String("SYMBIAN_SBSV2") || makefileGenerator == QLatin1String("SYMBIAN_UNIX")) { m_isBuildUsingSbsV2 = (makefileGenerator == QLatin1String("SYMBIAN_SBSV2")); if (S60Manager::instance()) { m_abis.append(ProjectExplorer::Abi(ProjectExplorer::Abi::ArmArchitecture, ProjectExplorer::Abi::SymbianOS, ProjectExplorer::Abi::UnknownFlavor, ProjectExplorer::Abi::ElfFormat, 32)); m_targetIds.insert(QLatin1String(Constants::S60_DEVICE_TARGET_ID)); m_targetIds.insert(QLatin1String(Constants::S60_EMULATOR_TARGET_ID)); } } else if (MaemoGlobal::isValidMaemo5QtVersion(this)) { m_abis.append(ProjectExplorer::Abi(ProjectExplorer::Abi::ArmArchitecture, ProjectExplorer::Abi::LinuxOS, ProjectExplorer::Abi::MaemoLinuxFlavor, ProjectExplorer::Abi::ElfFormat, 32)); m_targetIds.insert(QLatin1String(Constants::MAEMO5_DEVICE_TARGET_ID)); } else if (MaemoGlobal::isValidHarmattanQtVersion(this)) { m_abis.append(ProjectExplorer::Abi(ProjectExplorer::Abi::ArmArchitecture, ProjectExplorer::Abi::LinuxOS, ProjectExplorer::Abi::HarmattanLinuxFlavor, ProjectExplorer::Abi::ElfFormat, 32)); m_targetIds.insert(QLatin1String(Constants::HARMATTAN_DEVICE_TARGET_ID)); } else if (MaemoGlobal::isValidMeegoQtVersion(this)) { m_abis.append(ProjectExplorer::Abi(ProjectExplorer::Abi::ArmArchitecture, ProjectExplorer::Abi::LinuxOS, ProjectExplorer::Abi::MeegoLinuxFlavor, ProjectExplorer::Abi::ElfFormat, 32)); m_targetIds.insert(QLatin1String(Constants::MEEGO_DEVICE_TARGET_ID)); } else if (qmakeCXX.contains("g++") || qmakeCXX == "cl" || qmakeCXX == "icl" // intel cl || qmakeCXX == QLatin1String("icpc")) { m_abis = ProjectExplorer::Abi::abisOfBinary(coreLibrary); #if defined (Q_OS_WIN) if (makefileGenerator == "MINGW") { QList tmp = m_abis; m_abis.clear(); foreach (const ProjectExplorer::Abi &abi, tmp) m_abis.append(ProjectExplorer::Abi(abi.architecture(), abi.os(), ProjectExplorer::Abi::WindowsMSysFlavor, abi.binaryFormat(), abi.wordWidth())); } #endif m_targetIds.insert(QLatin1String(Constants::DESKTOP_TARGET_ID)); } if (m_abis.isEmpty() && !coreLibrary.isEmpty()) { qWarning("Warning: Could not find ABI for '%s' ('%s', %s)/%s by looking at %s:" "Qt Creator does not know about the system includes, " "nor the system defines.", qPrintable(m_mkspecFullPath), qPrintable(displayName()), qPrintable(qmakeCommand()), qPrintable(qmakeCXX), qPrintable(coreLibrary)); } QStringList configValues = evaluator.values("CONFIG"); m_defaultConfigIsDebugAndRelease = false; foreach(const QString &value, configValues) { if (value == "debug") m_defaultConfigIsDebug = true; else if (value == "release") m_defaultConfigIsDebug = false; else if (value == "build_all") m_defaultConfigIsDebugAndRelease = true; } // Is this actually a simulator Qt? if (configValues.contains(QLatin1String("simulator"))) { m_targetIds.clear(); m_targetIds.insert(QLatin1String(Constants::QT_SIMULATOR_TARGET_ID)); } ProFileCacheManager::instance()->decRefCount(); // Set up systemroot if (supportsTargetId(Constants::MAEMO5_DEVICE_TARGET_ID) || supportsTargetId(Constants::HARMATTAN_DEVICE_TARGET_ID)) { if (m_systemRoot.isNull()) { QFile file(QDir::cleanPath(MaemoGlobal::targetRoot(this)) + QLatin1String("/information")); if (file.exists() && file.open(QIODevice::ReadOnly | QIODevice::Text)) { QTextStream stream(&file); while (!stream.atEnd()) { const QString &line = stream.readLine().trimmed(); const QStringList &list = line.split(QLatin1Char(' ')); if (list.count() <= 1) continue; if (list.at(0) == QLatin1String("sysroot")) { m_systemRoot = MaemoGlobal::maddeRoot(this) + QLatin1String("/sysroots/") + list.at(1); } } } } } else if (supportsTargetId(Constants::S60_DEVICE_TARGET_ID) || supportsTargetId(Constants::S60_EMULATOR_TARGET_ID)) { if (m_systemRoot.isEmpty()) m_validSystemRoot = false; if (!m_systemRoot.endsWith(QLatin1Char('/'))) m_systemRoot.append(QLatin1Char('/')); QFileInfo cppheader(m_systemRoot + QLatin1String("epoc32/include/stdapis/string.h")); if (!cppheader.exists()) m_validSystemRoot = false; } else { m_systemRoot = QLatin1String(""); } } QString QtVersion::resolveLink(const QString &path) const { QFileInfo f(path); int links = 16; while (links-- && f.isSymLink()) f.setFile(f.symLinkTarget()); if (links <= 0) return QString(); return f.filePath(); } QString QtVersion::qtCorePath() const { QList dirs; dirs << QDir(libraryInstallPath()) << QDir(versionInfo().value(QLatin1String("QT_INSTALL_BINS"))); QFileInfoList staticLibs; foreach (const QDir &d, dirs) { 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 const QString libName = file.left(file.lastIndexOf('.')); return info.absoluteFilePath() + '/' + libName; } 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") || file.endsWith(".lib")) staticLibs.append(info); else if (file.endsWith(QLatin1String(".dll")) || file.endsWith(QString::fromLatin1(".so.") + qtVersionString()) || file.endsWith(QLatin1Char('.') + qtVersionString() + QLatin1String(".dylib"))) return info.absoluteFilePath(); } } } } // Return path to first static library found: if (!staticLibs.isEmpty()) return staticLibs.at(0).absoluteFilePath(); return QString(); } QString QtVersion::sbsV2Directory() const { return m_sbsV2Directory; } void QtVersion::setSbsV2Directory(const QString &directory) { QDir dir(directory); if (dir.exists(QLatin1String("sbs"))) { m_sbsV2Directory = dir.absolutePath(); return; } dir.cd("bin"); if (dir.exists(QLatin1String("sbs"))) { m_sbsV2Directory = dir.absolutePath(); return; } m_sbsV2Directory = directory; } void QtVersion::addToEnvironment(Utils::Environment &env) const { // Generic: env.set("QTDIR", QDir::toNativeSeparators(versionInfo().value("QT_INSTALL_DATA"))); env.prependOrSetPath(versionInfo().value("QT_INSTALL_BINS")); // Symbian specific: if (supportsTargetId(Constants::S60_DEVICE_TARGET_ID) || supportsTargetId(Constants::S60_EMULATOR_TARGET_ID)) { // Generic Symbian environment: QString epocRootPath(systemRoot()); QDir epocDir(epocRootPath); // Clean up epoc root path for the environment: if (!epocRootPath.endsWith(QLatin1Char('/'))) epocRootPath.append(QLatin1Char('/')); if (!isBuildWithSymbianSbsV2()) { #ifdef Q_OS_WIN if (epocRootPath.count() > 2 && epocRootPath.at(0).toLower() >= QLatin1Char('a') && epocRootPath.at(0).toLower() <= QLatin1Char('z') && epocRootPath.at(1) == QLatin1Char(':')) { epocRootPath = epocRootPath.mid(2); } #endif } env.set(QLatin1String("EPOCROOT"), QDir::toNativeSeparators(epocRootPath)); env.prependOrSetPath(epocDir.filePath(QLatin1String("epoc32/tools"))); // e.g. make.exe // Windows only: if (ProjectExplorer::Abi::hostAbi().os() == ProjectExplorer::Abi::WindowsOS) { QString winDir = QLatin1String(qgetenv("WINDIR")); if (!winDir.isEmpty()) env.prependOrSetPath(QDir(winDir).filePath(QLatin1String("system32"))); if (epocDir.exists(QLatin1String("epoc32/gcc/bin"))) env.prependOrSetPath(epocDir.filePath(QLatin1String("epoc32/gcc/bin"))); // e.g. cpp.exe, *NOT* gcc.exe // Find perl in the special Symbian flavour: if (epocDir.exists(QLatin1String("../../tools/perl/bin"))) { epocDir.cd(QLatin1String("../../tools/perl/bin")); env.prependOrSetPath(epocDir.absolutePath()); } else { env.prependOrSetPath(epocDir.filePath(QLatin1String("perl/bin"))); } } // SBSv2: if (isBuildWithSymbianSbsV2()) { QString sbsHome(env.value(QLatin1String("SBS_HOME"))); QString sbsConfig = sbsV2Directory(); if (!sbsConfig.isEmpty()) { env.prependOrSetPath(sbsConfig); // SBS_HOME is the path minus the trailing /bin: env.set(QLatin1String("SBS_HOME"), QDir::toNativeSeparators(sbsConfig.left(sbsConfig.count() - 4))); // We need this for Qt 4.6.3 compatibility } else if (!sbsHome.isEmpty()) { env.prependOrSetPath(sbsHome + QLatin1String("/bin")); } } } } static const char *S60_EPOC_HEADERS[] = { "include", "mkspecs/common/symbian", "epoc32/include", "epoc32/include/osextensions/stdapis", "epoc32/include/osextensions/stdapis/sys", "epoc32/include/stdapis", "epoc32/include/stdapis/sys", "epoc32/include/osextensions/stdapis/stlport", "epoc32/include/stdapis/stlport", "epoc32/include/oem", "epoc32/include/middleware", "epoc32/include/domain/middleware", "epoc32/include/osextensions", "epoc32/include/domain/osextensions", "epoc32/include/domain/osextensions/loc", "epoc32/include/domain/middleware/loc", "epoc32/include/domain/osextensions/loc/sc", "epoc32/include/domain/middleware/loc/sc" }; QList QtVersion::systemHeaderPathes() const { QList result; if (supportsTargetId(Constants::S60_DEVICE_TARGET_ID) || supportsTargetId(Constants::S60_EMULATOR_TARGET_ID)) { QString root = systemRoot() + QLatin1Char('/'); const int count = sizeof(S60_EPOC_HEADERS) / sizeof(const char *); for (int i = 0; i < count; ++i) { const QDir dir(root + QLatin1String(S60_EPOC_HEADERS[i])); if (dir.exists()) result.append(ProjectExplorer::HeaderPath(dir.absolutePath(), ProjectExplorer::HeaderPath::GlobalHeaderPath)); } } return result; } int QtVersion::uniqueId() const { return m_id; } int QtVersion::getUniqueId() { return QtVersionManager::instance()->getUniqueId(); } bool QtVersion::isValid() const { updateVersionInfo(); updateAbiAndMkspec(); return m_id != -1 && !qmakeCommand().isEmpty() && !displayName().isEmpty() && !m_notInstalled && m_versionInfo.contains("QT_INSTALL_BINS") && (!m_mkspecFullPath.isEmpty() || !m_abiUpToDate) && !m_abis.isEmpty() && m_qmakeIsExecutable && m_validSystemRoot; } bool QtVersion::toolChainAvailable(const QString &id) const { if (!isValid()) return false; if (id == QLatin1String(Constants::S60_EMULATOR_TARGET_ID)) { QList tcList = ProjectExplorer::ToolChainManager::instance()->toolChains(); foreach (ProjectExplorer::ToolChain *tc, tcList) { if (tc->id().startsWith(QLatin1String(Constants::WINSCW_TOOLCHAIN_ID))) return true; } return false; } else if (id == QLatin1String(Constants::S60_DEVICE_TARGET_ID)) { QList tcList = ProjectExplorer::ToolChainManager::instance()->toolChains(); foreach (ProjectExplorer::ToolChain *tc, tcList) { if (!tc->id().startsWith(Qt4ProjectManager::Constants::WINSCW_TOOLCHAIN_ID)) return true; } return false; } foreach (const ProjectExplorer::Abi &abi, qtAbis()) if (!ProjectExplorer::ToolChainManager::instance()->findToolChains(abi).isEmpty()) return true; return false; } QString QtVersion::invalidReason() const { if (isValid()) return QString(); 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 (displayName().isEmpty()) return QCoreApplication::translate("QtVersion", "Qt version has no name"); if (m_notInstalled) return QCoreApplication::translate("QtVersion", "Qt version is not properly installed, please run make install"); if (!m_versionInfo.contains("QT_INSTALL_BINS")) return QCoreApplication::translate("QtVersion", "Could not determine the path to the binaries of the Qt installation, maybe the qmake path is wrong?"); if (m_abiUpToDate && m_mkspecFullPath.isEmpty()) return QCoreApplication::translate("QtVersion", "The default mkspec symlink is broken."); if (m_abiUpToDate && m_abis.isEmpty()) return QCoreApplication::translate("QtVersion", "Failed to detect the ABI(s) used by the Qt version."); if (!m_validSystemRoot) return QCoreApplication::translate("QtVersion", "The \"Open C/C++ plugin\" is not installed in the Symbian SDK or the Symbian SDK path is misconfigured"); return QString(); } QString QtVersion::description() const { if (!isValid()) return invalidReason(); QSet targets = supportedTargetIds(); QString envs; if (targets.contains(Constants::DESKTOP_TARGET_ID)) envs = QCoreApplication::translate("QtVersion", "Desktop", "Qt Version is meant for the desktop"); else if (targets.contains(Constants::S60_DEVICE_TARGET_ID) || targets.contains(Constants::S60_EMULATOR_TARGET_ID)) envs = QCoreApplication::translate("QtVersion", "Symbian", "Qt Version is meant for Symbian"); else if (targets.contains(Constants::MAEMO5_DEVICE_TARGET_ID)) envs = QCoreApplication::translate("QtVersion", "Maemo", "Qt Version is meant for Maemo5"); else if (targets.contains(Constants::HARMATTAN_DEVICE_TARGET_ID)) envs = QCoreApplication::translate("QtVersion", "Harmattan ", "Qt Version is meant for Harmattan"); else if (targets.contains(Constants::MEEGO_DEVICE_TARGET_ID)) envs = QCoreApplication::translate("QtVersion", "Meego", "Qt Version is meant for Meego"); else if (targets.contains(Constants::QT_SIMULATOR_TARGET_ID)) envs = QCoreApplication::translate("QtVersion", "Qt Simulator", "Qt Version is meant for Qt Simulator"); else envs = QCoreApplication::translate("QtVersion", "unkown", "No idea what this Qt Version is meant for!"); return QCoreApplication::translate("QtVersion", "Qt version %1, using mkspec %2 (%3)") .arg(qtVersionString(), mkspec(), envs); } QtVersion::QmakeBuildConfigs QtVersion::defaultBuildConfig() const { updateAbiAndMkspec(); QtVersion::QmakeBuildConfigs result = QtVersion::QmakeBuildConfig(0); if (m_defaultConfigIsDebugAndRelease) result = QtVersion::BuildAll; if (m_defaultConfigIsDebug) result = result | QtVersion::DebugBuild; return result; } bool QtVersion::hasGdbDebuggingHelper() const { updateVersionInfo(); return m_hasDebuggingHelper; } bool QtVersion::hasQmlDump() const { updateVersionInfo(); return m_hasQmlDump; } bool QtVersion::hasQmlDebuggingLibrary() const { updateVersionInfo(); return m_hasQmlDebuggingLibrary; } bool QtVersion::hasQmlObserver() const { updateVersionInfo(); return m_hasQmlObserver; } Utils::Environment QtVersion::qmlToolsEnvironment() const { // FIXME: This seems broken! Utils::Environment environment = Utils::Environment::systemEnvironment(); addToEnvironment(environment); // add preferred tool chain, as that is how the tools are built, compare QtVersion::buildDebuggingHelperLibrary QList alltc = ProjectExplorer::ToolChainManager::instance()->findToolChains(qtAbis().at(0)); if (!alltc.isEmpty()) alltc.first()->addToEnvironment(environment); return environment; } QString QtVersion::gdbDebuggingHelperLibrary() const { QString qtInstallData = versionInfo().value("QT_INSTALL_DATA"); if (qtInstallData.isEmpty()) return QString(); return DebuggingHelperLibrary::debuggingHelperLibraryByInstallData(qtInstallData); } QString QtVersion::qmlDumpTool(bool debugVersion) const { QString qtInstallData = versionInfo().value("QT_INSTALL_DATA"); if (qtInstallData.isEmpty()) return QString(); return QmlDumpTool::toolByInstallData(qtInstallData, debugVersion); } QString QtVersion::qmlDebuggingHelperLibrary(bool debugVersion) const { QString qtInstallData = versionInfo().value("QT_INSTALL_DATA"); if (qtInstallData.isEmpty()) return QString(); return QmlDebuggingLibrary::libraryByInstallData(qtInstallData, debugVersion); } QString QtVersion::qmlObserverTool() const { QString qtInstallData = versionInfo().value("QT_INSTALL_DATA"); if (qtInstallData.isEmpty()) return QString(); return QmlObserverTool::toolByInstallData(qtInstallData); } QStringList QtVersion::debuggingHelperLibraryLocations() const { QString qtInstallData = versionInfo().value("QT_INSTALL_DATA"); if (qtInstallData.isEmpty()) return QStringList(); return DebuggingHelperLibrary::locationsByInstallData(qtInstallData); } bool QtVersion::supportsBinaryDebuggingHelper() const { if (!isValid()) return false; return qtAbis().at(0).os() != ProjectExplorer::Abi::SymbianOS; } bool QtVersion::hasDocumentation() const { updateVersionInfo(); return m_hasDocumentation; } QString QtVersion::documentationPath() const { updateVersionInfo(); return m_versionInfo["QT_INSTALL_DOCS"]; } bool QtVersion::hasDemos() const { updateVersionInfo(); return m_hasDemos; } QString QtVersion::demosPath() const { updateVersionInfo(); return m_versionInfo["QT_INSTALL_DEMOS"]; } QString QtVersion::headerInstallPath() const { updateVersionInfo(); return m_versionInfo["QT_INSTALL_HEADERS"]; } QString QtVersion::frameworkInstallPath() const { #ifdef Q_OS_MAC updateVersionInfo(); return m_versionInfo["QT_INSTALL_LIBS"]; #else return QString(); #endif } QString QtVersion::libraryInstallPath() const { updateVersionInfo(); return m_versionInfo["QT_INSTALL_LIBS"]; } bool QtVersion::hasExamples() const { updateVersionInfo(); return m_hasExamples; } QString QtVersion::examplesPath() const { updateVersionInfo(); return m_versionInfo["QT_INSTALL_EXAMPLES"]; } void QtVersion::invalidateCache() { m_versionInfoUpToDate = false; } /////////////// // QtVersionNumber /////////////// QtVersionNumber::QtVersionNumber(int ma, int mi, int p) : majorVersion(ma), minorVersion(mi), patchVersion(p) { } QtVersionNumber::QtVersionNumber(const QString &versionString) { if (!checkVersionString(versionString)) { majorVersion = minorVersion = patchVersion = -1; return; } QStringList parts = versionString.split(QLatin1Char('.')); majorVersion = parts.at(0).toInt(); minorVersion = parts.at(1).toInt(); patchVersion = parts.at(2).toInt(); } QtVersionNumber::QtVersionNumber() { majorVersion = minorVersion = patchVersion = -1; } bool QtVersionNumber::checkVersionString(const QString &version) const { int dots = 0; QString validChars = "0123456789."; foreach (const QChar &c, version) { if (!validChars.contains(c)) return false; if (c == '.') ++dots; } if (dots != 2) return false; return true; } bool QtVersionNumber::operator <(const QtVersionNumber &b) const { if (majorVersion < b.majorVersion) return true; if (majorVersion > b.majorVersion) return false; if (minorVersion < b.minorVersion) return true; if (minorVersion > b.minorVersion) return false; if (patchVersion < b.patchVersion) return true; return false; } 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; }