diff --git a/src/plugins/projectexplorer/environment.cpp b/src/plugins/projectexplorer/environment.cpp index ac592254d723e400e72d4151ef190ffd8cb16323..07b3091be6f9a4410920a2c43862cc51962a283d 100644 --- a/src/plugins/projectexplorer/environment.cpp +++ b/src/plugins/projectexplorer/environment.cpp @@ -123,14 +123,15 @@ void Environment::appendOrSet(const QString &key, const QString &value, const QS #else const QString &_key = key; #endif - QMap<QString, QString>::const_iterator it = m_values.constFind(key); - if (it == m_values.constEnd()) { + QMap<QString, QString>::iterator it = m_values.find(key); + if (it == m_values.end()) { m_values.insert(_key, value); } else { - QString tmp = *it + sep + value; - m_values.insert(_key, tmp); + // Append unless it is already there + const QString toAppend = sep + value; + if (!it.value().endsWith(toAppend)) + it.value().append(toAppend); } - } void Environment::prependOrSet(const QString&key, const QString &value, const QString &sep) @@ -140,12 +141,14 @@ void Environment::prependOrSet(const QString&key, const QString &value, const QS #else const QString &_key = key; #endif - QMap<QString, QString>::const_iterator it = m_values.constFind(key); - if (it == m_values.constEnd()) { + QMap<QString, QString>::iterator it = m_values.find(key); + if (it == m_values.end()) { m_values.insert(_key, value); } else { - QString tmp = value + sep + *it; - m_values.insert(_key, tmp); + // Prepend unless it is already there + const QString toPrepend = value + sep; + if (!it.value().startsWith(toPrepend)) + it.value().prepend(toPrepend); } } diff --git a/src/plugins/projectexplorer/toolchain.cpp b/src/plugins/projectexplorer/toolchain.cpp index edafb72de6bc8a21962930fac09f83720fc1329b..d5bed5999d6e512981c24ff9a3a2b8b31c97114a 100644 --- a/src/plugins/projectexplorer/toolchain.cpp +++ b/src/plugins/projectexplorer/toolchain.cpp @@ -126,7 +126,7 @@ QString ToolChain::toolChainName(ToolChainType tc) return QCoreApplication::translate("ToolChain", "GCCE"); case GCCE_GNUPOC: return QCoreApplication::translate("ToolChain", "GCCE/GnuPoc"); - case RVCT_ARMV6_GNUPOC: + case RVCT_ARMV5_GNUPOC: return QCoreApplication::translate("ToolChain", "RVCT (ARMV6)/GnuPoc"); case RVCT_ARMV5: return QCoreApplication::translate("ToolChain", "RVCT (ARMV5)"); diff --git a/src/plugins/projectexplorer/toolchain.h b/src/plugins/projectexplorer/toolchain.h index f13b2c1d5c4a2e9cbe8d43e74f4033f77c2698cb..ced91fc06856ad7c9188c3c8e5dd16a3b0994cba 100644 --- a/src/plugins/projectexplorer/toolchain.h +++ b/src/plugins/projectexplorer/toolchain.h @@ -86,7 +86,7 @@ public: RVCT_ARMV6 = 8, GCC_MAEMO = 9, GCCE_GNUPOC = 10, - RVCT_ARMV6_GNUPOC = 11, + RVCT_ARMV5_GNUPOC = 11, LAST_VALID = 11, OTHER = 200, UNKNOWN = 201, diff --git a/src/plugins/qt4projectmanager/qt-s60/rvcttoolchain.cpp b/src/plugins/qt4projectmanager/qt-s60/rvcttoolchain.cpp index 852180677a97b4829d1b392eb7f41951012ddfc3..441ca934708e7d6d73c21e2645e7536fd4a700cf 100644 --- a/src/plugins/qt4projectmanager/qt-s60/rvcttoolchain.cpp +++ b/src/plugins/qt4projectmanager/qt-s60/rvcttoolchain.cpp @@ -30,11 +30,19 @@ #include "rvcttoolchain.h" #include "rvctparser.h" +#include <utils/qtcassert.h> + #include <QtCore/QProcess> +#include <QtCore/QProcessEnvironment> +#include <QtCore/QDebug> +#include <QtCore/QFileInfo> +#include <QtCore/QDir> using namespace ProjectExplorer; using namespace Qt4ProjectManager::Internal; +static const char rvctBinaryC[] = "armcc"; + RVCTToolChain::RVCTToolChain(const S60Devices::Device &device, ToolChain::ToolChainType type) : m_mixin(device), m_type(type), @@ -45,6 +53,54 @@ RVCTToolChain::RVCTToolChain(const S60Devices::Device &device, ToolChain::ToolCh { } +// Return the environment variable indicating the RVCT version +// 'RVCT<major><minor>BIN' +QByteArray RVCTToolChain::rvctBinEnvironmentVariable() +{ + static QByteArray binVar; + // Grep the environment list + if (binVar.isEmpty()) { + const QRegExp regex(QLatin1String("^(RVCT\\d\\dBIN)=.*$")); + QTC_ASSERT(regex.isValid(), return QByteArray()); + foreach(const QString &v, QProcessEnvironment::systemEnvironment().toStringList()) { + if (regex.exactMatch(v)) { + binVar = regex.cap(1).toLocal8Bit(); + break; + } + } + } + return binVar; +} + +// Return binary path as pointed to by RVCT<X><X>BIN +QString RVCTToolChain::rvctBinPath() +{ + static QString binPath; + if (binPath.isEmpty()) { + const QByteArray binVar = rvctBinEnvironmentVariable(); + if (!binVar.isEmpty()) { + const QByteArray binPathB = qgetenv(binVar); + if (!binPathB.isEmpty()) { + const QFileInfo fi(QString::fromLocal8Bit(binPathB)); + if (fi.isDir()) + binPath = fi.absoluteFilePath(); + } + } + } + return binPath; +} + +// Return binary expanded by path or resort to PATH +QString RVCTToolChain::rvctBinary() +{ + QString executable = QLatin1String(rvctBinaryC); +#ifdef Q_OS_WIN + executable += QLatin1String(".exe"); +#endif + const QString binPath = rvctBinPath(); + return binPath.isEmpty() ? executable : (binPath + QLatin1Char('/') + executable); +} + ToolChain::ToolChainType RVCTToolChain::type() const { return m_type; @@ -54,6 +110,7 @@ void RVCTToolChain::updateVersion() { if (m_versionUpToDate) return; + m_versionUpToDate = true; m_major = 0; m_minor = 0; @@ -62,13 +119,19 @@ void RVCTToolChain::updateVersion() ProjectExplorer::Environment env = ProjectExplorer::Environment::systemEnvironment(); addToEnvironment(env); armcc.setEnvironment(env.toStringList()); - armcc.start("armcc", QStringList()); + const QString binary = rvctBinary(); + armcc.start(rvctBinary(), QStringList()); + if (!armcc.waitForStarted()) { + qWarning("Unable to run rvct binary '%s' when trying to determine version.", qPrintable(binary)); + return; + } armcc.closeWriteChannel(); armcc.waitForFinished(); - QString versionLine = armcc.readAllStandardOutput(); - versionLine += armcc.readAllStandardError(); - QRegExp versionRegExp("RVCT(\\d*)\\.(\\d*).*\\[Build.(\\d*)\\]", - Qt::CaseInsensitive); + QString versionLine = QString::fromLocal8Bit(armcc.readAllStandardOutput()); + versionLine += QString::fromLocal8Bit(armcc.readAllStandardError()); + const QRegExp versionRegExp(QLatin1String("RVCT(\\d*)\\.(\\d*).*\\[Build.(\\d*)\\]"), + Qt::CaseInsensitive); + QTC_ASSERT(versionRegExp.isValid(), return); if (versionRegExp.indexIn(versionLine) != -1) { m_major = versionRegExp.cap(1).toInt(); m_minor = versionRegExp.cap(2).toInt(); @@ -113,8 +176,8 @@ QList<HeaderPath> RVCTToolChain::systemHeaderPaths() if (!rvctInclude.isEmpty()) m_systemHeaderPaths.append(HeaderPath(rvctInclude, HeaderPath::GlobalHeaderPath)); switch (m_type) { - case ProjectExplorer::ToolChain::RVCT_ARMV6_GNUPOC: - m_systemHeaderPaths += m_mixin.gnuPocHeaderPaths(); + case ProjectExplorer::ToolChain::RVCT_ARMV5_GNUPOC: + m_systemHeaderPaths += m_mixin.gnuPocRvctHeaderPaths(m_major, m_minor); break; default: m_systemHeaderPaths += m_mixin.epocHeaderPaths(); @@ -124,11 +187,66 @@ QList<HeaderPath> RVCTToolChain::systemHeaderPaths() return m_systemHeaderPaths; } +static inline QStringList headerPathToStringList(const QList<ProjectExplorer::HeaderPath> &hl) +{ + QStringList rc; + foreach(const ProjectExplorer::HeaderPath &hp, hl) + rc.push_back(hp.path()); + return rc; +} + +// Expand an RVCT variable, such as RVCT22BIN, by some new values +void RVCTToolChain::addToRVCTPathVariable(const QString &postfix, const QStringList &values, + ProjectExplorer::Environment &env) const +{ + // get old values + const QChar separator = QLatin1Char(','); + const QString variable = QString::fromLatin1("RVCT%1%2%3").arg(m_major).arg(m_minor).arg(postfix); + const QString oldValueS = env.value(variable); + const QStringList oldValue = oldValueS.isEmpty() ? QStringList() : oldValueS.split(separator); + // merge new values + QStringList newValue = oldValue; + foreach(const QString &v, values) { + const QString normalized = QDir::toNativeSeparators(v); + if (!newValue.contains(normalized)) + newValue.push_back(normalized); + } + if (newValue != oldValue) + env.set(variable, newValue.join(QString(separator))); +} + +// Figure out lib path via +QStringList RVCTToolChain::libPaths() +{ + const QByteArray binLocation = qgetenv(rvctBinEnvironmentVariable()); + if (binLocation.isEmpty()) + return QStringList(); + const QString pathRoot = QFileInfo(QString::fromLocal8Bit(binLocation)).path(); + QStringList rc; + rc.push_back(pathRoot + QLatin1String("/lib")); + rc.push_back(pathRoot + QLatin1String("/lib/armlib")); + return rc; +} + void RVCTToolChain::addToEnvironment(ProjectExplorer::Environment &env) { + updateVersion(); switch (m_type) { - case ProjectExplorer::ToolChain::RVCT_ARMV6_GNUPOC: + case ProjectExplorer::ToolChain::RVCT_ARMV5_GNUPOC: { m_mixin.addGnuPocToEnvironment(&env); + // setup RVCT22INC, LIB + addToRVCTPathVariable(QLatin1String("INC"), + headerPathToStringList(m_mixin.gnuPocRvctHeaderPaths(m_major, m_minor)), + env); + addToRVCTPathVariable(QLatin1String("LIB"), + libPaths() + m_mixin.gnuPocRvctLibPaths(5, true), + env); + // Add rvct to path and set locale to 'C' + const QString binPath = rvctBinPath(); + if (!binPath.isEmpty()) + env.prependOrSetPath(binPath); + env.set(QLatin1String("LANG"), QString(QLatin1Char('C'))); + } break; default: m_mixin.addEpocToEnvironment(&env); diff --git a/src/plugins/qt4projectmanager/qt-s60/rvcttoolchain.h b/src/plugins/qt4projectmanager/qt-s60/rvcttoolchain.h index 01ab0a444b3620095376fb98c6730ace545f2868..0e7950f9dbc2159d2a951a0eacdb4730bc4732e1 100644 --- a/src/plugins/qt4projectmanager/qt-s60/rvcttoolchain.h +++ b/src/plugins/qt4projectmanager/qt-s60/rvcttoolchain.h @@ -49,10 +49,19 @@ public: QString makeCommand() const; ProjectExplorer::IOutputParser *outputParser() const; + // Return the environment variable indicating the RVCT version + // 'RVCT<major><minor>BIN' and its setting + static QByteArray rvctBinEnvironmentVariable(); + static QString rvctBinPath(); + static QString rvctBinary(); + protected: bool equals(ToolChain *other) const; private: + void addToRVCTPathVariable(const QString &postfix, const QStringList &values, + ProjectExplorer::Environment &env) const; + static QStringList libPaths(); void updateVersion(); const S60ToolChainMixin m_mixin; diff --git a/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.cpp b/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.cpp index 5493e50b3d8216e3828fd99da328ec8f6882450f..0c2dfd61f26dfd110155909ca74d5787e1ad96d6 100644 --- a/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.cpp +++ b/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.cpp @@ -179,9 +179,18 @@ ProjectExplorer::ToolChain::ToolChainType S60DeviceRunConfiguration::toolChainTy bool S60DeviceRunConfiguration::isEnabled(ProjectExplorer::BuildConfiguration *configuration) const { - Qt4BuildConfiguration *qt4bc = static_cast<Qt4BuildConfiguration *>(configuration); - const ToolChain::ToolChainType type = qt4bc->toolChainType(); - return type == ToolChain::GCCE || type == ToolChain::RVCT_ARMV5 || type == ToolChain::RVCT_ARMV6; + const Qt4BuildConfiguration *qt4bc = static_cast<const Qt4BuildConfiguration *>(configuration); + switch (qt4bc->toolChainType()) { + case ToolChain::GCCE: + case ToolChain::RVCT_ARMV5: + case ToolChain::RVCT_ARMV6: + case ToolChain::GCCE_GNUPOC: + case ToolChain::RVCT_ARMV5_GNUPOC: + return true; + default: + break; + } + return false; } QWidget *S60DeviceRunConfiguration::configurationWidget() @@ -468,8 +477,8 @@ RunConfiguration *S60DeviceRunConfigurationFactory::clone(Target *parent, RunCon S60DeviceRunControlBase::S60DeviceRunControlBase(RunConfiguration *runConfiguration) : RunControl(runConfiguration), m_toolChain(ProjectExplorer::ToolChain::INVALID), - m_makesis(new QProcess(this)), - m_signsis(0), + m_makesisProcess(new QProcess(this)), + m_signsisProcess(0), m_releaseDeviceAfterLauncherFinish(false), m_handleDeviceRemoval(true), m_launcher(0) @@ -477,13 +486,13 @@ S60DeviceRunControlBase::S60DeviceRunControlBase(RunConfiguration *runConfigurat // connect for automatically reporting the "finished deploy" state to the progress manager connect(this, SIGNAL(finished()), this, SLOT(reportDeployFinished())); - connect(m_makesis, SIGNAL(readyReadStandardError()), + connect(m_makesisProcess, SIGNAL(readyReadStandardError()), this, SLOT(readStandardError())); - connect(m_makesis, SIGNAL(readyReadStandardOutput()), + connect(m_makesisProcess, SIGNAL(readyReadStandardOutput()), this, SLOT(readStandardOutput())); - connect(m_makesis, SIGNAL(error(QProcess::ProcessError)), + connect(m_makesisProcess, SIGNAL(error(QProcess::ProcessError)), this, SLOT(makesisProcessFailed())); - connect(m_makesis, SIGNAL(finished(int,QProcess::ExitStatus)), + connect(m_makesisProcess, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(makesisProcessFinished())); S60DeviceRunConfiguration *s60runConfig = qobject_cast<S60DeviceRunConfiguration *>(runConfiguration); @@ -509,28 +518,30 @@ S60DeviceRunControlBase::S60DeviceRunControlBase(RunConfiguration *runConfigurat const S60Devices::Device device = S60Manager::instance()->deviceForQtVersion(activeBuildConf->qtVersion()); switch (m_toolChain) { case ProjectExplorer::ToolChain::GCCE_GNUPOC: - case ProjectExplorer::ToolChain::RVCT_ARMV6_GNUPOC: { + case ProjectExplorer::ToolChain::RVCT_ARMV5_GNUPOC: { // 'sis' is a make target here. Set up with correct environment ProjectExplorer::ToolChain *toolchain = activeBuildConf->toolChain(); m_makesisTool = toolchain->makeCommand(); m_toolsDirectory = device.epocRoot + QLatin1String("/epoc32/tools"); ProjectExplorer::Environment env = ProjectExplorer::Environment::systemEnvironment(); + env.set(QLatin1String("QT_SIS_CERTIFICATE"), signSisCertificate()); + env.set(QLatin1String("QT_SIS_KEY"), signSisKey()); toolchain->addToEnvironment(env); - m_makesis->setEnvironment(env.toStringList()); + m_makesisProcess->setEnvironment(env.toStringList()); } break; default: m_toolsDirectory = device.toolsRoot + QLatin1String("/epoc32/tools"); m_makesisTool = m_toolsDirectory + "/makesis.exe"; // Set up signing packages - m_signsis = new QProcess(this); - connect(m_signsis, SIGNAL(readyReadStandardError()), + m_signsisProcess = new QProcess(this); + connect(m_signsisProcess, SIGNAL(readyReadStandardError()), this, SLOT(readStandardError())); - connect(m_signsis, SIGNAL(readyReadStandardOutput()), + connect(m_signsisProcess, SIGNAL(readyReadStandardOutput()), this, SLOT(readStandardOutput())); - connect(m_signsis, SIGNAL(error(QProcess::ProcessError)), + connect(m_signsisProcess, SIGNAL(error(QProcess::ProcessError)), this, SLOT(signsisProcessFailed())); - connect(m_signsis, SIGNAL(finished(int,QProcess::ExitStatus)), + connect(m_signsisProcess, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(signsisProcessFinished())); break; } @@ -589,7 +600,7 @@ void S60DeviceRunControlBase::start() QStringList makeSisArgs; switch (m_toolChain) { case ProjectExplorer::ToolChain::GCCE_GNUPOC: - case ProjectExplorer::ToolChain::RVCT_ARMV6_GNUPOC: + case ProjectExplorer::ToolChain::RVCT_ARMV5_GNUPOC: makeSisArgs.push_back(QLatin1String("sis")); break; default: @@ -602,11 +613,11 @@ void S60DeviceRunControlBase::start() break; } - m_makesis->setWorkingDirectory(m_workingDirectory); + m_makesisProcess->setWorkingDirectory(m_workingDirectory); emit addToOutputWindow(this, tr("%1 %2").arg(QDir::toNativeSeparators(m_makesisTool), m_packageFile)); if (debug) qDebug() << m_makesisTool << makeSisArgs << m_workingDirectory; - m_makesis->start(m_makesisTool, makeSisArgs, QIODevice::ReadOnly); + m_makesisProcess->start(m_makesisTool, makeSisArgs, QIODevice::ReadOnly); } static inline void stopProcess(QProcess *p) @@ -622,17 +633,17 @@ static inline void stopProcess(QProcess *p) void S60DeviceRunControlBase::stop() { - if (m_makesis) - stopProcess(m_makesis); - if (m_signsis) - stopProcess(m_signsis); + if (m_makesisProcess) + stopProcess(m_makesisProcess); + if (m_signsisProcess) + stopProcess(m_signsisProcess); if (m_launcher) m_launcher->terminate(); } bool S60DeviceRunControlBase::isRunning() const { - return m_makesis->state() != QProcess::NotRunning; + return m_makesisProcess->state() != QProcess::NotRunning; } void S60DeviceRunControlBase::readStandardError() @@ -672,12 +683,12 @@ bool S60DeviceRunControlBase::createPackageFileFromTemplate(QString *errorMessag void S60DeviceRunControlBase::makesisProcessFailed() { - processFailed(m_makesisTool, m_makesis->error()); + processFailed(m_makesisTool, m_makesisProcess->error()); } void S60DeviceRunControlBase::makesisProcessFinished() { - if (m_makesis->exitCode() != 0) { + if (m_makesisProcess->exitCode() != 0) { error(this, tr("An error occurred while creating the package.")); stop(); emit finished(); @@ -686,7 +697,7 @@ void S60DeviceRunControlBase::makesisProcessFinished() m_deployProgress->setProgressValue(PROGRESS_PACKAGECREATED); switch (m_toolChain) { case ProjectExplorer::ToolChain::GCCE_GNUPOC: - case ProjectExplorer::ToolChain::RVCT_ARMV6_GNUPOC: + case ProjectExplorer::ToolChain::RVCT_ARMV5_GNUPOC: startDeployment(); break; default: @@ -695,32 +706,45 @@ void S60DeviceRunControlBase::makesisProcessFinished() } } +QString S60DeviceRunControlBase::signSisKey() const +{ + const QString key = m_useCustomSignature ? m_customKeyPath: + m_qtDir + QLatin1String("/src/s60installs/selfsigned.key"); + return QDir::toNativeSeparators(key); +} + +QString S60DeviceRunControlBase::signSisCertificate() const +{ + const QString cert = m_useCustomSignature ? m_customSignaturePath : + m_qtDir + QLatin1String("/src/s60installs/selfsigned.cer"); + return QDir::toNativeSeparators(cert); +} + void S60DeviceRunControlBase::startSigning() { - QString signsisTool = m_toolsDirectory + QLatin1String("/signsis.exe"); - QString sisFile = QFileInfo(m_baseFileName + QLatin1String(".sis")).fileName(); - QString sisxFile = QFileInfo(m_baseFileName + QLatin1String(".sisx")).fileName(); - QString signature = (m_useCustomSignature ? m_customSignaturePath - : m_qtDir + QLatin1String("/src/s60installs/selfsigned.cer")); - QString key = (m_useCustomSignature ? m_customKeyPath - : m_qtDir + QLatin1String("/src/s60installs/selfsigned.key")); + // Signis creates a signed package ('.sisx') from a '.sis' + // using certificate and key. + QString signsisTool = m_toolsDirectory + QLatin1String("/signsis"); +#ifdef Q_OS_WIN + signsisTool += QLatin1String(".exe"); +#endif + const QString sisFile = QFileInfo(m_baseFileName + QLatin1String(".sis")).fileName(); + const QString sisxFile = sisFile + QLatin1Char('x'); QStringList arguments; - arguments << sisFile - << sisxFile << QDir::toNativeSeparators(signature) - << QDir::toNativeSeparators(key); - m_signsis->setWorkingDirectory(m_workingDirectory); + arguments << sisFile << sisxFile << signSisCertificate() << signSisKey(); + m_signsisProcess->setWorkingDirectory(m_workingDirectory); emit addToOutputWindow(this, tr("%1 %2").arg(QDir::toNativeSeparators(signsisTool), arguments.join(QString(QLatin1Char(' '))))); - m_signsis->start(signsisTool, arguments, QIODevice::ReadOnly); + m_signsisProcess->start(signsisTool, arguments, QIODevice::ReadOnly); } void S60DeviceRunControlBase::signsisProcessFailed() { - processFailed("signsis.exe", m_signsis->error()); + processFailed("signsis.exe", m_signsisProcess->error()); } void S60DeviceRunControlBase::signsisProcessFinished() { - if (m_signsis->exitCode() != 0) { + if (m_signsisProcess->exitCode() != 0) { error(this, tr("An error occurred while creating the package.")); stop(); emit finished(); diff --git a/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.h b/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.h index 3b5699095b651726241d229fa5467a01764b0d56..4fa2a06ef4513cb7e1a062bc1a8ec1ae79cba303 100644 --- a/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.h +++ b/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.h @@ -156,7 +156,7 @@ public: /* S60DeviceRunControlBase: Builds the package and starts launcher * to deploy. Subclasses can configure the launcher to run or start a debugger. * Building the package comprises for: - * GnuPoc: run 'make sis' + * GnuPoc: run 'make sis' with environment variables for signing set * Other: run the makesis.exe tool, run signsis */ class S60DeviceRunControlBase : public ProjectExplorer::RunControl @@ -211,6 +211,8 @@ private: bool createPackageFileFromTemplate(QString *errorMessage); void startSigning(); void startDeployment(); + QString signSisKey() const; + QString signSisCertificate() const; ProjectExplorer::ToolChain::ToolChainType m_toolChain; QString m_serialPortName; @@ -229,8 +231,8 @@ private: bool m_useCustomSignature; QString m_customSignaturePath; QString m_customKeyPath; - QProcess *m_makesis; - QProcess *m_signsis; + QProcess *m_makesisProcess; + QProcess *m_signsisProcess; QString m_makesisTool; QString m_packageFile; bool m_releaseDeviceAfterLauncherFinish; diff --git a/src/plugins/qt4projectmanager/qt-s60/s60devices.cpp b/src/plugins/qt4projectmanager/qt-s60/s60devices.cpp index 3ca9ba569962f411e106ba7bfd84fc03a7a86101..1f9cb0df25e4e48f3dac596fd32d17e1613a91f4 100644 --- a/src/plugins/qt4projectmanager/qt-s60/s60devices.cpp +++ b/src/plugins/qt4projectmanager/qt-s60/s60devices.cpp @@ -85,7 +85,7 @@ S60Devices::S60Devices(QObject *parent) } // GNU-Poc stuff -static const char *gnuPocRootC = "GNUPOC_ROOT"; +static const char *epocRootC = "EPOCROOT"; static inline QString msgEnvVarNotSet(const char *var) { @@ -100,28 +100,22 @@ static inline QString msgEnvVarDirNotExist(const QString &dir, const char *var) bool S60Devices::readLinux() { // Detect GNUPOC_ROOT/EPOC ROOT - const QByteArray gnuPocRootA = qgetenv(gnuPocRootC); - if (gnuPocRootA.isEmpty()) { - m_errorString = msgEnvVarNotSet(gnuPocRootC); + const QByteArray epocRootA = qgetenv(epocRootC); + if (epocRootA.isEmpty()) { + m_errorString = msgEnvVarNotSet(epocRootC); return false; } - const QDir gnuPocRootDir(QString::fromLocal8Bit(gnuPocRootA)); - if (!gnuPocRootDir.exists()) { - m_errorString = msgEnvVarDirNotExist(gnuPocRootDir.absolutePath(), gnuPocRootC); + const QDir epocRootDir(QString::fromLocal8Bit(epocRootA)); + if (!epocRootDir.exists()) { + m_errorString = msgEnvVarDirNotExist(epocRootDir.absolutePath(), epocRootC); return false; } - const QDir epocDir(gnuPocRootDir.absolutePath() + QLatin1String("/symbian-sdks/5.0")); - if (!epocDir.exists()) { - m_errorString = QString::fromLatin1("EPOC could not be found at %1.").arg(epocDir.absolutePath()); - return false; - } // Check Qt Device device; device.id = device.name = QLatin1String("GnuPoc"); - device.epocRoot = epocDir.absolutePath(); - device.toolsRoot = gnuPocRootDir.absolutePath(); + device.toolsRoot = device.epocRoot = epocRootDir.absolutePath(); device.isDefault = true; m_devices.push_back(device); return true; @@ -233,40 +227,73 @@ bool S60Devices::readWin() return true; } -bool S60Devices::detectQtForDevices() +// Detect a Qt version that is installed into a Symbian SDK +static QString detect_SDK_installedQt(const QString &epocRoot) { + const QString coreLibDllFileName = epocRoot + QLatin1String("/epoc32/release/winscw/udeb/QtCore.dll"); + QFile coreLibDllFile(coreLibDllFileName); + if (!coreLibDllFile.exists() || !coreLibDllFile.open(QIODevice::ReadOnly)) + return false; + // Do not normalize these backslashes since they are in ARM binaries: const QByteArray indicator("\\src\\corelib\\kernel\\qobject.h"); const int indicatorlength = indicator.size(); - for (int i = 0; i < m_devices.size(); ++i) { - if (!m_devices.at(i).qt.isEmpty()) - continue; - QFile qtDll(QString("%1/epoc32/release/winscw/udeb/QtCore.dll").arg(m_devices.at(i).epocRoot)); - if (!qtDll.exists() || !qtDll.open(QIODevice::ReadOnly)) { - m_devices[i].qt.clear(); - continue; - } - QByteArray buffer; - int index = -1; - while (!qtDll.atEnd()) { - buffer = qtDll.read(10000); - index = buffer.indexOf(indicator); - if (index >= 0) - break; - if (!qtDll.atEnd()) - qtDll.seek(qtDll.pos()-indicatorlength); - } - int lastIndex = index; - while (index >= 0 && buffer.at(index)) - --index; - if (index < 0) { // this is untested - } else { - index += 2; // the 0 and another byte for some reason - m_devices[i].qt = QDir(buffer.mid(index, lastIndex-index)).absolutePath(); + const int chunkSize = 10000; + + int index = -1; + QByteArray buffer; + while (true) { + buffer = coreLibDllFile.read(chunkSize); + index = buffer.indexOf(indicator); + if (index >= 0) + break; + if (buffer.size() < chunkSize || coreLibDllFile.atEnd()) + return QString(); + coreLibDllFile.seek(coreLibDllFile.pos() - indicatorlength); + } + coreLibDllFile.close(); + + int lastIndex = index; + while (index >= 0 && buffer.at(index)) + --index; + if (index < 0) + return QString(); + + index += 2; // the 0 and another byte for some reason + return QDir(QString::fromLatin1(buffer.mid(index, lastIndex-index))).absolutePath(); +} + +// GnuPoc: Detect a Qt version that is symlinked/below an SDK +// TODO: Find a proper way of doing that +static QString detectGnuPocQt(const QString &epocRoot) +{ + const QFileInfo fi(epocRoot + QLatin1String("/qt")); + if (!fi.exists()) + return QString(); + if (fi.isSymLink()) + return QFileInfo(fi.symLinkTarget()).absoluteFilePath(); + return fi.absoluteFilePath(); +} + +bool S60Devices::detectQtForDevices() +{ + bool changed = false; + const int deviceCount = m_devices.size(); + for (int i = 0; i < deviceCount; ++i) { + Device &device = m_devices[i]; + if (device.qt.isEmpty()) { + device.qt = detect_SDK_installedQt(device.epocRoot); + if (device.qt.isEmpty()) + device.qt = detectGnuPocQt(device.epocRoot); + if (device.qt.isEmpty()) { + qWarning("Unable to detect Qt version for '%s'.", qPrintable(device.epocRoot)); + } else { + changed = true; + } } - qtDll.close(); } - emit qtVersionsChanged(); + if (changed) + emit qtVersionsChanged(); return true; } @@ -389,15 +416,49 @@ void S60ToolChainMixin::addEpocToEnvironment(ProjectExplorer::Environment *env) env->set(QLatin1String("EPOCROOT"), QDir::toNativeSeparators(epocRootPath)); } +static const char *gnuPocHeaderPathsC[] = { + "epoc32/include", "epoc32/include/variant", "epoc32/include/stdapis", + "epoc32/include/stdapis/stlport" }; + QList<ProjectExplorer::HeaderPath> S60ToolChainMixin::gnuPocHeaderPaths() const { - return QList<ProjectExplorer::HeaderPath>(); // TODO: + QList<ProjectExplorer::HeaderPath> rc; + const QString root = m_device.epocRoot + QLatin1Char('/'); + const int count = sizeof(gnuPocHeaderPathsC)/sizeof(const char *); + for (int i = 0; i < count; i++) + rc.push_back(ProjectExplorer::HeaderPath(root + QLatin1String(gnuPocHeaderPathsC[i]), + ProjectExplorer::HeaderPath::GlobalHeaderPath)); + return rc; +} + +QStringList S60ToolChainMixin::gnuPocRvctLibPaths(int armver, bool debug) const +{ + QStringList rc; + QString root; + QTextStream(&root) << m_device.epocRoot << "epoc32/release/armv" << armver << '/'; + rc.push_back(root + QLatin1String("lib")); + rc.push_back(root + (debug ? QLatin1String("udeb") : QLatin1String("urel"))); + return rc; +} + +QList<ProjectExplorer::HeaderPath> S60ToolChainMixin::gnuPocRvctHeaderPaths(int major, int minor) const +{ + // Additional header for rvct + QList<ProjectExplorer::HeaderPath> rc = gnuPocHeaderPaths(); + QString rvctHeader; + QTextStream(&rvctHeader) << m_device.epocRoot << "/epoc32/include/rvct" << major << '_' << minor; + rc.push_back(ProjectExplorer::HeaderPath(rvctHeader, ProjectExplorer::HeaderPath::GlobalHeaderPath)); + return rc; } void S60ToolChainMixin::addGnuPocToEnvironment(ProjectExplorer::Environment *env) const { - env->prependOrSetPath(QDir::toNativeSeparators(m_device.toolsRoot + QLatin1String("/bin"))); - env->set(QLatin1String("EPOCROOT"), QDir::toNativeSeparators(S60Devices::cleanedRootPath(m_device.epocRoot))); + env->prependOrSetPath(QDir::toNativeSeparators(m_device.toolsRoot + QLatin1String("/epoc32/tools"))); + const QString epocRootVar = QLatin1String("EPOCROOT"); + // No trailing slash is required here, so, do not perform path cleaning. + // The variable also should be set since it is currently used for autodetection. + if (env->find(epocRootVar) == env->constEnd()) + env->set(epocRootVar, m_device.epocRoot); } QDebug operator<<(QDebug db, const S60Devices::Device &d) diff --git a/src/plugins/qt4projectmanager/qt-s60/s60devices.h b/src/plugins/qt4projectmanager/qt-s60/s60devices.h index 7bd9d03dd0402cc3a47516781e8c4118ddfa9058..226c070c965c6a372f33beddf2398fe0614f79c4 100644 --- a/src/plugins/qt4projectmanager/qt-s60/s60devices.h +++ b/src/plugins/qt4projectmanager/qt-s60/s60devices.h @@ -95,6 +95,8 @@ public: // GnuPoc QList<ProjectExplorer::HeaderPath> gnuPocHeaderPaths() const; + QList<ProjectExplorer::HeaderPath> gnuPocRvctHeaderPaths(int major, int minor) const; + QStringList gnuPocRvctLibPaths(int armver, bool debug) const; void addGnuPocToEnvironment(ProjectExplorer::Environment *env) const; bool equals(const S60ToolChainMixin &rhs) const; diff --git a/src/plugins/qt4projectmanager/qt-s60/s60devicespreferencepane.cpp b/src/plugins/qt4projectmanager/qt-s60/s60devicespreferencepane.cpp index 51d942f2e630cf4beb85869a1c525186b5e9f001..1cccbdf1665980a0c254279666c42afc3946f43b 100644 --- a/src/plugins/qt4projectmanager/qt-s60/s60devicespreferencepane.cpp +++ b/src/plugins/qt4projectmanager/qt-s60/s60devicespreferencepane.cpp @@ -32,8 +32,10 @@ #include <qt4projectmanager/qt4projectmanagerconstants.h> +#include <utils/qtcassert.h> + #include <QtCore/QDir> -#include <QtDebug> +#include <QtCore/QtDebug> using namespace Qt4ProjectManager; using namespace Qt4ProjectManager::Internal; @@ -56,7 +58,7 @@ S60DevicesWidget::~S60DevicesWidget() void S60DevicesWidget::updateDevices() { m_devices->read(); - Q_ASSERT(m_devices->detectQtForDevices()); + QTC_ASSERT(m_devices->detectQtForDevices(), return); updateDevicesList(); } diff --git a/src/plugins/qt4projectmanager/qt-s60/s60manager.cpp b/src/plugins/qt4projectmanager/qt-s60/s60manager.cpp index e163b8f894428f7374fbad48c6a4c20cc73300a5..1eb4f43a7de26d26e6c1325a512d76b0ec10acb1 100644 --- a/src/plugins/qt4projectmanager/qt-s60/s60manager.cpp +++ b/src/plugins/qt4projectmanager/qt-s60/s60manager.cpp @@ -138,6 +138,11 @@ S60Manager::~S60Manager() } } +bool S60Manager::hasRvctCompiler() +{ + return !RVCTToolChain::rvctBinEnvironmentVariable().isEmpty(); +} + void S60Manager::addAutoReleasedObject(QObject *o) { ExtensionSystem::PluginManager::instance()->addObject(o); diff --git a/src/plugins/qt4projectmanager/qt-s60/s60manager.h b/src/plugins/qt4projectmanager/qt-s60/s60manager.h index c807534f595e4eb397d52e4dc46f6170a14f616c..82587949350336eda01ed09b4dfce88f461c6628 100644 --- a/src/plugins/qt4projectmanager/qt-s60/s60manager.h +++ b/src/plugins/qt4projectmanager/qt-s60/s60manager.h @@ -60,6 +60,8 @@ public: S60Devices::Device deviceForQtVersion(const Qt4ProjectManager::QtVersion *version) const; QString deviceIdFromDetectionSource(const QString &autoDetectionSource) const; + static bool hasRvctCompiler(); + private slots: void updateQtVersions(); diff --git a/src/plugins/qt4projectmanager/qt4buildconfiguration.cpp b/src/plugins/qt4projectmanager/qt4buildconfiguration.cpp index 3a5f5d8ddb961dd19c57faee68267926145d4669..9a6f24db26d0d40ab2027cb4c3326451ffa7be47 100644 --- a/src/plugins/qt4projectmanager/qt4buildconfiguration.cpp +++ b/src/plugins/qt4projectmanager/qt4buildconfiguration.cpp @@ -305,13 +305,13 @@ QString Qt4BuildConfiguration::defaultMakeTarget() const switch (tc->type()) { case ToolChain::GCCE: - case ToolChain::GCCE_GNUPOC: return symbianMakeTarget(buildConfig, QLatin1String("gcce")); case ToolChain::RVCT_ARMV5: return symbianMakeTarget(buildConfig, QLatin1String("armv5")); case ToolChain::RVCT_ARMV6: - case ToolChain::RVCT_ARMV6_GNUPOC: return symbianMakeTarget(buildConfig, QLatin1String("armv6")); + case ToolChain::RVCT_ARMV5_GNUPOC: + case ToolChain::GCCE_GNUPOC: default: break; } diff --git a/src/plugins/qt4projectmanager/qt4runconfiguration.cpp b/src/plugins/qt4projectmanager/qt4runconfiguration.cpp index 417778848cceeae0a09e934f940751a44ff266dd..fe7e10a551cf093885817efb790de50569147e1b 100644 --- a/src/plugins/qt4projectmanager/qt4runconfiguration.cpp +++ b/src/plugins/qt4projectmanager/qt4runconfiguration.cpp @@ -139,7 +139,7 @@ bool Qt4RunConfiguration::isEnabled(ProjectExplorer::BuildConfiguration *configu switch (type) { case ToolChain::MSVC: case ToolChain::WINCE: case ToolChain::GCC: case ToolChain::MinGW: - case ToolChain::GCCE_GNUPOC: case ToolChain::RVCT_ARMV6_GNUPOC: + case ToolChain::GCCE_GNUPOC: case ToolChain::RVCT_ARMV5_GNUPOC: case ToolChain::OTHER: case ToolChain::UNKNOWN: case ToolChain::INVALID: enabled = true; diff --git a/src/plugins/qt4projectmanager/qtversionmanager.cpp b/src/plugins/qt4projectmanager/qtversionmanager.cpp index 54574d637a4e0f39667527dc0d540906681ff563..32d0184428995a73d99d6b306a84e5c4d66e1378 100644 --- a/src/plugins/qt4projectmanager/qtversionmanager.cpp +++ b/src/plugins/qt4projectmanager/qtversionmanager.cpp @@ -1231,12 +1231,13 @@ void QtVersion::updateToolChainAndMkspec() const m_toolChains << ToolChainPtr(ProjectExplorer::ToolChain::createWinCEToolChain(msvcVersion(), wincePlatformName)); m_targetIds.insert(DESKTOP_TARGET_ID); } else if (makefileGenerator == QLatin1String("SYMBIAN_ABLD") || - makefileGenerator == QLatin1String("SYMBIAN_SBSV2")) { + makefileGenerator == QLatin1String("SYMBIAN_SBSV2") || + makefileGenerator == QLatin1String("SYMBIAN_UNIX")) { if (S60Manager *s60mgr = S60Manager::instance()) { # ifdef Q_OS_WIN m_targetIds.insert(QLatin1String(S60_DEVICE_TARGET_ID)); m_toolChains << ToolChainPtr(s60mgr->createGCCEToolChain(this)); - if (!qgetenv("RVCT22BIN").isEmpty()) + if (S60Manager::hasRvctCompiler()) m_toolChains << ToolChainPtr(s60mgr->createRVCTToolChain(this, ProjectExplorer::ToolChain::RVCT_ARMV5)) << ToolChainPtr(s60mgr->createRVCTToolChain(this, ProjectExplorer::ToolChain::RVCT_ARMV6)); if (!mwcDirectory().isEmpty()) { @@ -1244,8 +1245,9 @@ void QtVersion::updateToolChainAndMkspec() const m_targetIds.insert(QLatin1String(S60_EMULATOR_TARGET_ID)); } # else - m_toolChains << ToolChainPtr(s60mgr->createGCCE_GnuPocToolChain(this)) - << ToolChainPtr(s60mgr->createRVCTToolChain(this, ProjectExplorer::ToolChain::RVCT_ARMV6_GNUPOC)); + if (S60Manager::hasRvctCompiler()) + m_toolChains << ToolChainPtr(s60mgr->createRVCTToolChain(this, ProjectExplorer::ToolChain::RVCT_ARMV5_GNUPOC)); + m_toolChains << ToolChainPtr(s60mgr->createGCCE_GnuPocToolChain(this)); m_targetIds.insert(QLatin1String(S60_DEVICE_TARGET_ID)); # endif }