Symbian/Linux: Enable building with makefile-based system.

- Autodetect SDK by environment variable EPOCROOT and qt directory
below.
- Environment::appendOrSet/prependOrSet: Avoid duplicate entries
- Rename toolchain enumeration value
- Adapt S60ToolChainMixin to new GnuPoc setup, provide routines for
  all required variables.
- RVCTToolChain: Make RVCT detection smarter (Check for RVCT<v1><v2>BIN
  variable). Set all required variables in case of RVCTToolChain/GnuPoc
- QtVersionManager: Detect toolchain and Qt version properly, make S60
  device run config accept toolchain.
- Modify S60DeviceRunControl to execute 'make sis'
- Modify S60Devices::detectQt...() to check for Qt installed into SDK
  first and symlink as fallback.
This commit is contained in:
Friedemann Kleint
2010-02-17 17:38:48 +01:00
parent e5eff803a5
commit 7c9c99dcf0
15 changed files with 348 additions and 118 deletions

View File

@@ -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);
}
}

View File

@@ -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)");

View File

@@ -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,

View File

@@ -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*)\\]",
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);

View File

@@ -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;

View File

@@ -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();

View File

@@ -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;

View File

@@ -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,39 +227,72 @@ 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;
const int chunkSize = 10000;
int index = -1;
while (!qtDll.atEnd()) {
buffer = qtDll.read(10000);
QByteArray buffer;
while (true) {
buffer = coreLibDllFile.read(chunkSize);
index = buffer.indexOf(indicator);
if (index >= 0)
break;
if (!qtDll.atEnd())
qtDll.seek(qtDll.pos()-indicatorlength);
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) { // this is untested
} else {
if (index < 0)
return QString();
index += 2; // the 0 and another byte for some reason
m_devices[i].qt = QDir(buffer.mid(index, lastIndex-index)).absolutePath();
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();
}
}
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)

View File

@@ -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;

View File

@@ -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();
}

View File

@@ -138,6 +138,11 @@ S60Manager::~S60Manager()
}
}
bool S60Manager::hasRvctCompiler()
{
return !RVCTToolChain::rvctBinEnvironmentVariable().isEmpty();
}
void S60Manager::addAutoReleasedObject(QObject *o)
{
ExtensionSystem::PluginManager::instance()->addObject(o);

View File

@@ -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();

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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
}