From ff14295b47a63c66e11498e74f807a6660bc979e Mon Sep 17 00:00:00 2001 From: SteveKing Date: Wed, 16 Nov 2011 21:15:48 +0000 Subject: Fix the support for WinCE. Change-Id: Id08dab3128b9ff943c68b442e8cadf14caaee204 Reviewed-by: hjk --- src/plugins/projectexplorer/wincetoolchain.cpp | 488 +++++++++++++++++++++++++ 1 file changed, 488 insertions(+) create mode 100644 src/plugins/projectexplorer/wincetoolchain.cpp (limited to 'src/plugins/projectexplorer/wincetoolchain.cpp') diff --git a/src/plugins/projectexplorer/wincetoolchain.cpp b/src/plugins/projectexplorer/wincetoolchain.cpp new file mode 100644 index 0000000000..d3913524cf --- /dev/null +++ b/src/plugins/projectexplorer/wincetoolchain.cpp @@ -0,0 +1,488 @@ +/************************************************************************** +** +** 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 info@qt.nokia.com. +** +**************************************************************************/ + +#include "wincetoolchain.h" + +#include "msvcparser.h" +#include "projectexplorerconstants.h" +#include "headerpath.h" + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#define KEY_ROOT "ProjectExplorer.WinCEToolChain." +static const char debuggerCommandKeyC[] = KEY_ROOT"Debugger"; +static const char msvcVerKeyC[] = KEY_ROOT"MSVCVer"; +static const char ceVerKeyC[] = KEY_ROOT"CEVer"; +static const char binPathKeyC[] = KEY_ROOT"BinPath"; +static const char includePathKeyC[] = KEY_ROOT"IncludePath"; +static const char libPathKeyC[] = KEY_ROOT"LibPath"; +static const char supportedAbiKeyC[] = KEY_ROOT"SupportedAbi"; +static const char vcVarsKeyC[] = KEY_ROOT"VCVars"; + +enum { debug = 0 }; + +namespace ProjectExplorer { +namespace Internal { + +// -------------------------------------------------------------------------- +// Helpers: +// -------------------------------------------------------------------------- + +// Just decodes from the integer version to the string used in Qt mkspecs +static QString findMsvcVer(int version) +{ + if (10 == version) + return QLatin1String("msvc2010"); + else if (9 == version) + return QLatin1String("msvc2008");; + + return QLatin1String("msvc2005"); +} + + +// Windows: Expand the delayed evaluation references returned by the +// SDK setup scripts: "PATH=$(Path);foo". Some values might expand +// to empty and should not be added +static QString winExpandDelayedEnvReferences(QString in, const Utils::Environment &env) +{ + const QString firstDelimit = QLatin1String("$("); + const QChar secondDelimit = QLatin1Char(')'); + for (int pos = 0; pos < in.size(); ) { + // Replace "$(REF)" by its value in process environment + pos = in.indexOf(firstDelimit, pos); + if (pos == -1) + break; + const int replaceStart = pos + firstDelimit.size(); + const int nextPos = in.indexOf(secondDelimit, replaceStart); + if (nextPos == -1) + break; + const QString var = in.mid(replaceStart, nextPos - replaceStart); + QString replacement = env.value(var.toUpper()); + if (replacement.isEmpty()) { + qWarning() << "No replacement for var: " << var; + pos = nextPos; + } + else { + // Not sure about this, but we need to account for the case where + // the end of the replacement doesn't have the directory seperator and + // neither does the start of the insert. This solution assumes: + // 1) Having \\ in a path is valid (it is on WinXP) + // 2) We're only replacing in paths. This will cause problems if there's + // a replace of a string + if (!replacement.endsWith('\\')) + replacement += '\\'; + + in.replace(pos, nextPos + 1 - pos, replacement); + pos += replacement.size(); + } + } + return in; +} + +// This is pretty much the same as the ReadEnvironmentSetting in the msvctoolchain.cpp, but +// this takes account of the library, binary and include paths to replace the vcvars versions +// with the ones for this toolchain. +Utils::Environment WinCEToolChain::readEnvironmentSetting(Utils::Environment& env) const +{ + Utils::Environment result = env; + if (!QFileInfo(m_vcvarsBat).exists()) + return result; + + // Get the env pairs + QMap envPairs; + + if (!generateEnvironmentSettings(env, m_vcvarsBat, QString(), envPairs)) + return result; + + QMap::const_iterator envPairIter; + for (envPairIter = envPairs.begin(); envPairIter!=envPairs.end(); ++envPairIter) { + // Replace the env values with those from the WinCE SDK + QString varValue = envPairIter.value(); + if ("PATH" == envPairIter.key()) + varValue = m_binPath + ";" + varValue; + else if ("INCLUDE" == envPairIter.key()) + varValue = m_includePath; + else if ("LIB" == envPairIter.key()) + varValue = m_libPath; + + if (!varValue.isEmpty()) + result.set(envPairIter.key(), varValue); + } + + + // Now loop round and do the delayed expansion + Utils::Environment::const_iterator envIter = result.constBegin(); + while (envIter != result.constEnd()) { + const QString key = result.key(envIter); + const QString unexpandedValue = result.value(envIter); + + const QString expandedValue = winExpandDelayedEnvReferences(unexpandedValue, result); + + result.set(key, expandedValue); + + ++envIter; + } + + if (debug) { + const QStringList newVars = result.toStringList(); + const QStringList oldVars = env.toStringList(); + QDebug nsp = qDebug().nospace(); + foreach (const QString &n, newVars) { + if (!oldVars.contains(n)) + nsp << n << '\n'; + } + } + return result; +} + +// Used to parse an SDK entry in the config file and extract information about this SDK +static bool parseSDK(QXmlStreamReader& theReader, + Abi::Architecture& sdkArch, + QString& sdkName, + QString& ceVer, + QString& binPath, + QString& includePath, + QString& libPath) +{ + sdkArch = Abi::UnknownArchitecture; + sdkName = ""; + + // Loop through until either the end of the file or until is gets to the next + // end element. + while (!theReader.atEnd()) { + theReader.readNext(); + + if (theReader.isEndElement()) { + // Got to the end element so return... + if (theReader.name() == "Platform") + return (sdkArch!=Abi::UnknownArchitecture && !sdkName.isEmpty()); + } else if (theReader.isStartElement()) { + const QStringRef elemName = theReader.name(); + if (elemName == "PlatformName") { + sdkName = theReader.readElementText(); + } else if (elemName == "Directories") { + // Populate the paths from this element. Note: we remove the + // $(PATH) from the binPath as this will be pre-pended in code + binPath = theReader.attributes().value("Path").toString(); + binPath.remove("$(PATH)"); + includePath = theReader.attributes().value("Include").toString(); + libPath = theReader.attributes().value("Library").toString(); + } else if (elemName == "OSMajorVersion") { + // Qt only supports CE5 and higher so drop out here if this version is + // invalid + ceVer = theReader.readElementText(); + if (ceVer.toInt() < 5) { + qDebug() << "Ignoring SDK as Qt only support CE 5 and higher."; + return false; + } + } else if (elemName == "Macro") { + // Pull out the architecture from the macro values. + if (theReader.attributes().value("Name") == "ARCHFAM") { + const QStringRef archFam = theReader.attributes().value("Value"); + + if (archFam == "ARM") + sdkArch = Abi::ArmArchitecture; + else if (archFam == "x86") + sdkArch = Abi::X86Architecture; + else if (archFam == "MIPS") + sdkArch = Abi::MipsArchitecture; + } + } + } + } + + // If we've got to here then the end of the file has been reached before the + // end of element tag, so return error. + return false; +} + +// -------------------------------------------------------------------------- +// WinCEToolChain +// -------------------------------------------------------------------------- + +WinCEToolChain::WinCEToolChain(const QString &name, + const Abi &abi, + const QString &vcvarsBat, + const QString &msvcVer, + const QString &ceVer, + const QString &binPath, + const QString &includePath, + const QString &libPath, + bool autodetect) : + AbstractMsvcToolChain(QLatin1String(Constants::WINCE_TOOLCHAIN_ID), autodetect, abi, vcvarsBat), + m_msvcVer(msvcVer), + m_ceVer(ceVer), + m_binPath(binPath), + m_includePath(includePath), + m_libPath(libPath) +{ + Q_ASSERT(!name.isEmpty()); + Q_ASSERT(!m_binPath.isEmpty()); + Q_ASSERT(!m_includePath.isEmpty()); + Q_ASSERT(!m_libPath.isEmpty()); + + updateId(); + setDisplayName(name); +} + +WinCEToolChain::WinCEToolChain() : + AbstractMsvcToolChain(QLatin1String(Constants::WINCE_TOOLCHAIN_ID), false) +{ +} + +WinCEToolChain *WinCEToolChain::readFromMap(const QVariantMap &data) +{ + WinCEToolChain *tc = new WinCEToolChain; + if (tc->fromMap(data)) + return tc; + delete tc; + return 0; +} + +void WinCEToolChain::updateId() +{ + const QChar colon = QLatin1Char(':'); + QString id = QLatin1String(Constants::WINCE_TOOLCHAIN_ID); + id += colon; + id += m_msvcVer; + id += colon; + id += m_binPath; + id += colon; + id += m_includePath; + id += colon; + id += m_libPath; + id += colon; + id += m_debuggerCommand; + setId(id); +} + +QString WinCEToolChain::typeName() const +{ + return WinCEToolChainFactory::tr("WinCE"); +} + +QString WinCEToolChain::mkspec() const +{ + const QChar specSeperator('-'); + + QString specString = QLatin1String("wince"); + + specString += m_ceVer; + specString += specSeperator; + specString += Abi::toString(m_abi.architecture()); + specString += specSeperator; + specString += m_msvcVer; + + return specString; +} + + +QString WinCEToolChain::ceVer() const +{ + return m_ceVer; +} + + +QVariantMap WinCEToolChain::toMap() const +{ + QVariantMap data = ToolChain::toMap(); + if (!m_debuggerCommand.isEmpty()) + data.insert(QLatin1String(debuggerCommandKeyC), m_debuggerCommand); + + data.insert(QLatin1String(msvcVerKeyC), m_msvcVer); + data.insert(QLatin1String(ceVerKeyC), m_ceVer); + data.insert(QLatin1String(binPathKeyC), m_binPath); + data.insert(QLatin1String(includePathKeyC), m_includePath); + data.insert(QLatin1String(libPathKeyC), m_libPath); + data.insert(QLatin1String(vcVarsKeyC), m_vcvarsBat); + + data.insert(QLatin1String(supportedAbiKeyC), m_abi.toString()); + return data; +} + +bool WinCEToolChain::fromMap(const QVariantMap &data) +{ + if (!ToolChain::fromMap(data)) + return false; + + m_msvcVer = data.value(QLatin1String(msvcVerKeyC)).toString(); + m_ceVer = data.value(QLatin1String(ceVerKeyC)).toString(); + m_binPath = data.value(QLatin1String(binPathKeyC)).toString(); + m_includePath = data.value(QLatin1String(includePathKeyC)).toString(); + m_libPath = data.value(QLatin1String(libPathKeyC)).toString(); + m_vcvarsBat = data.value(QLatin1String(vcVarsKeyC)).toString(); + + m_debuggerCommand = data.value(QLatin1String(debuggerCommandKeyC)).toString(); + const QString abiString = data.value(QLatin1String(supportedAbiKeyC)).toString(); + m_abi = Abi(abiString); + updateId(); + + return isValid(); +} + +ToolChainConfigWidget *WinCEToolChain::configurationWidget() +{ + return new WinCEToolChainConfigWidget(this); +} + +ToolChain *WinCEToolChain::clone() const +{ + return new WinCEToolChain(*this); +} + + + +// -------------------------------------------------------------------------- +// WinCEToolChainFactory +// -------------------------------------------------------------------------- + +QString WinCEToolChainFactory::displayName() const +{ + return tr("WinCE"); +} + +QString WinCEToolChainFactory::id() const +{ + return QLatin1String(Constants::WINCE_TOOLCHAIN_ID); +} + + +QList WinCEToolChainFactory::autoDetect() +{ + QList results; + + // 1) Installed WinCEs + const QSettings vsRegistry( +#ifdef Q_OS_WIN64 + QLatin1String("HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\VisualStudio\\SxS\\VC7"), +#else + QLatin1String("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\SxS\\VC7"), +#endif + QSettings::NativeFormat); + + foreach (const QString &vsName, vsRegistry.allKeys()) { + // Scan for version major.minor + const int dotPos = vsName.indexOf(QLatin1Char('.')); + if (dotPos == -1) + continue; + + const QString path = QDir::fromNativeSeparators(vsRegistry.value(vsName).toString()); + const int version = vsName.left(dotPos).toInt(); + + // Check existence of various install scripts + const QString vcvars32bat = path + QLatin1String("bin/vcvars32.bat"); + QFile cePlatforms(path + "vcpackages/WCE.VCPlatform.config"); + + if (cePlatforms.exists()) { + const QString msvcVer = findMsvcVer(version); + cePlatforms.open(QIODevice::ReadOnly); + QXmlStreamReader platformReader(&cePlatforms); + + // Rip through the config file getting all of the installed platforms. + while (!platformReader.atEnd()) { + platformReader.readNext(); + if (platformReader.isStartElement()) { + if (platformReader.name() == "Platform") { + Abi::Architecture theArch; + QString thePlat; + QString binPath; + QString includePath; + QString libPath; + QString ceVer; + + if (parseSDK(platformReader, theArch, thePlat, ceVer, binPath, includePath, libPath)) { + WinCEToolChain *pChain = new WinCEToolChain(thePlat, + Abi(theArch, Abi::WindowsOS, Abi::WindowsCEFlavor, Abi::PEFormat, 32), + vcvars32bat, + msvcVer, + ceVer, + binPath, + includePath, + libPath, + true); + results.append(pChain); + } + } + } + } + } + } + + return results; +} + + +QString WinCEToolChain::autoDetectCdbDebugger(QStringList *checkedDirectories /* = 0 */) +{ + return QString(); +} + +bool WinCEToolChainFactory::canRestore(const QVariantMap &data) +{ + return idFromMap(data).startsWith(QLatin1String(Constants::WINCE_TOOLCHAIN_ID) + QLatin1Char(':')); +} + +ToolChain *WinCEToolChainFactory::restore(const QVariantMap &data) +{ + return WinCEToolChain::readFromMap(data); +} + +// -------------------------------------------------------------------------- +// WinCEToolChainConfigWidget +// -------------------------------------------------------------------------- + +WinCEToolChainConfigWidget::WinCEToolChainConfigWidget(ToolChain *tc) : + ToolChainConfigWidget(tc) +{ + WinCEToolChain *toolChain = static_cast(tc); + QTC_ASSERT(tc, return); + + QFormLayout *formLayout = new QFormLayout(this); + formLayout->addRow(tr("SDK:"), new QLabel(toolChain->displayName())); + formLayout->addRow(tr("WinCE Version:"), new QLabel(toolChain->ceVer())); + formLayout->addRow(tr("ABI:"), new QLabel(toolChain->targetAbi().toString())); + addErrorLabel(formLayout); +} + +} // namespace Internal +} // namespace ProjectExplorer -- cgit v1.2.1