Commit e35a754d authored by Friedemann Kleint's avatar Friedemann Kleint
Browse files

S60: Work towards new toolchains

Factor out the initialization setting up the environment and headers in
the RVCT/GCCE toolchains.
Modify the RunControl to be able to support different package
building/signing processes.
parent 7e655aab
......@@ -123,6 +123,10 @@ QString ToolChain::toolChainName(ToolChainType tc)
return QCoreApplication::translate("ToolChain", "WINSCW");
case GCCE:
return QCoreApplication::translate("ToolChain", "GCCE");
case GCCE_GNUPOC:
return QCoreApplication::translate("ToolChain", "GCCE/GnuPoc");
case RVCT_ARMV6_GNUPOC:
return QCoreApplication::translate("ToolChain", "RVCT (ARMV6)/GnuPoc");
case RVCT_ARMV5:
return QCoreApplication::translate("ToolChain", "RVCT (ARMV5)");
case RVCT_ARMV6:
......
......@@ -83,8 +83,10 @@ public:
GCCE = 6,
RVCT_ARMV5 = 7,
RVCT_ARMV6 = 8,
GCC_MAEMO = 9,
LAST_VALID = 10,
GCC_MAEMO = 9,
GCCE_GNUPOC = 10,
RVCT_ARMV6_GNUPOC = 11,
LAST_VALID = 11,
OTHER = 200,
UNKNOWN = 201,
INVALID = 202
......
......@@ -30,25 +30,32 @@
#include "gccetoolchain.h"
#include "qt4project.h"
#include <utils/qtcassert.h>
#include <QtCore/QDir>
#include <QtDebug>
#include <QtCore/QtDebug>
enum { debug = 0 };
using namespace ProjectExplorer;
using namespace Qt4ProjectManager::Internal;
GCCEToolChain::GCCEToolChain(S60Devices::Device device, const QString &gcceCommand)
: GccToolChain(gcceCommand),
m_deviceId(device.id),
m_deviceName(device.name),
m_deviceRoot(device.epocRoot),
GCCEToolChain::GCCEToolChain(const S60Devices::Device &device,
const QString &gcceCommand,
ProjectExplorer::ToolChain::ToolChainType type) :
GccToolChain(gcceCommand),
m_mixin(device),
m_type(type),
m_gcceCommand(gcceCommand)
{
QTC_ASSERT(m_type == ProjectExplorer::ToolChain::GCCE || m_type == ProjectExplorer::ToolChain::GCCE_GNUPOC, return)
if (debug)
qDebug() << "GCCEToolChain on" << m_type << m_mixin.device();
}
ToolChain::ToolChainType GCCEToolChain::type() const
{
return ToolChain::GCCE;
return m_type;
}
QByteArray GCCEToolChain::predefinedMacros()
......@@ -66,34 +73,44 @@ QList<HeaderPath> GCCEToolChain::systemHeaderPaths()
{
if (m_systemHeaderPaths.isEmpty()) {
GccToolChain::systemHeaderPaths();
m_systemHeaderPaths.append(HeaderPath(QString("%1\\epoc32\\include").arg(m_deviceRoot), HeaderPath::GlobalHeaderPath));
m_systemHeaderPaths.append(HeaderPath(QString("%1\\epoc32\\include\\stdapis").arg(m_deviceRoot), HeaderPath::GlobalHeaderPath));
m_systemHeaderPaths.append(HeaderPath(QString("%1\\epoc32\\include\\stdapis\\sys").arg(m_deviceRoot), HeaderPath::GlobalHeaderPath));
m_systemHeaderPaths.append(HeaderPath(QString("%1\\epoc32\\include\\variant").arg(m_deviceRoot), HeaderPath::GlobalHeaderPath));
switch (m_type) {
case ProjectExplorer::ToolChain::GCCE:
m_systemHeaderPaths += m_mixin.epocHeaderPaths();
break;
case ProjectExplorer::ToolChain::GCCE_GNUPOC:
m_systemHeaderPaths += m_mixin.gnuPocHeaderPaths();
break;
default:
break;
}
}
return m_systemHeaderPaths;
}
void GCCEToolChain::addToEnvironment(ProjectExplorer::Environment &env)
{
env.prependOrSetPath(QString("%1\\epoc32\\tools").arg(m_deviceRoot)); // e.g. make.exe
env.prependOrSetPath(QString("%1\\epoc32\\gcc\\bin").arg(m_deviceRoot)); // e.g. gcc.exe
env.prependOrSetPath(QFileInfo(m_gcceCommand).absolutePath());
env.set("EPOCDEVICE", QString("%1:%2").arg(m_deviceId, m_deviceName));
env.set("EPOCROOT", S60Devices::cleanedRootPath(m_deviceRoot));
switch (m_type) {
case ProjectExplorer::ToolChain::GCCE:
m_mixin.addEpocToEnvironment(&env);
env.prependOrSetPath(QFileInfo(m_gcceCommand).absolutePath());
case ProjectExplorer::ToolChain::GCCE_GNUPOC:
break;
default:
m_mixin.addGnuPocToEnvironment(&env);
break;
}
}
QString GCCEToolChain::makeCommand() const
{
return "make";
return QLatin1String("make");
}
bool GCCEToolChain::equals(ToolChain *other) const
bool GCCEToolChain::equals(ToolChain *otherIn) const
{
GCCEToolChain *otherGCCE = static_cast<GCCEToolChain *>(other);
return (other->type() == type()
&& m_deviceId == otherGCCE->m_deviceId
&& m_deviceName == otherGCCE->m_deviceName
&& m_deviceRoot == otherGCCE->m_deviceRoot
&& m_gcceCommand == otherGCCE->m_gcceCommand);
if (otherIn->type() != type())
return false;
const GCCEToolChain *other = static_cast<const GCCEToolChain *>(otherIn);
return m_mixin == other->m_mixin
&& m_gcceCommand == other->m_gcceCommand;
}
......@@ -40,20 +40,23 @@ namespace Internal {
class GCCEToolChain : public ProjectExplorer::GccToolChain
{
public:
GCCEToolChain(S60Devices::Device device, const QString &gcceCommand);
explicit GCCEToolChain(const S60Devices::Device &device,
const QString &gcceCommand,
ProjectExplorer::ToolChain::ToolChainType type);
QByteArray predefinedMacros();
QList<ProjectExplorer::HeaderPath> systemHeaderPaths();
void addToEnvironment(ProjectExplorer::Environment &env);
ProjectExplorer::ToolChain::ToolChainType type() const;
QString makeCommand() const;
virtual QList<ProjectExplorer::HeaderPath> systemHeaderPaths();
virtual void addToEnvironment(ProjectExplorer::Environment &env);
virtual ProjectExplorer::ToolChain::ToolChainType type() const;
virtual QString makeCommand() const;
protected:
bool equals(ToolChain *other) const;
virtual bool equals(ToolChain *other) const;
private:
QString m_deviceId;
QString m_deviceName;
QString m_deviceRoot;
QString m_gcceCommand;
private:
const S60ToolChainMixin m_mixin;
const ProjectExplorer::ToolChain::ToolChainType m_type;
const QString m_gcceCommand;
};
} // namespace Internal
......
......@@ -33,12 +33,13 @@
using namespace ProjectExplorer;
using namespace Qt4ProjectManager::Internal;
RVCTToolChain::RVCTToolChain(S60Devices::Device device, ToolChain::ToolChainType type)
: m_versionUpToDate(false),
m_deviceId(device.id),
m_deviceName(device.name),
m_deviceRoot(device.epocRoot),
m_type(type)
RVCTToolChain::RVCTToolChain(const S60Devices::Device &device, ToolChain::ToolChainType type) :
m_mixin(device),
m_type(type),
m_versionUpToDate(false),
m_major(0),
m_minor(0),
m_build(0)
{
}
......@@ -109,31 +110,40 @@ QList<HeaderPath> RVCTToolChain::systemHeaderPaths()
QString rvctInclude = env.value(QString::fromLatin1("RVCT%1%2INC").arg(m_major).arg(m_minor));
if (!rvctInclude.isEmpty())
m_systemHeaderPaths.append(HeaderPath(rvctInclude, HeaderPath::GlobalHeaderPath));
m_systemHeaderPaths.append(HeaderPath(QString("%1\\epoc32\\include").arg(m_deviceRoot), HeaderPath::GlobalHeaderPath));
m_systemHeaderPaths.append(HeaderPath(QString("%1\\epoc32\\include\\stdapis").arg(m_deviceRoot), HeaderPath::GlobalHeaderPath));
m_systemHeaderPaths.append(HeaderPath(QString("%1\\epoc32\\include\\stdapis\\sys").arg(m_deviceRoot), HeaderPath::GlobalHeaderPath));
m_systemHeaderPaths.append(HeaderPath(QString("%1\\epoc32\\include\\variant").arg(m_deviceRoot), HeaderPath::GlobalHeaderPath));
switch (m_type) {
case ProjectExplorer::ToolChain::RVCT_ARMV6_GNUPOC:
m_systemHeaderPaths += m_mixin.gnuPocHeaderPaths();
break;
default:
m_systemHeaderPaths += m_mixin.epocHeaderPaths();
break;
}
}
return m_systemHeaderPaths;
}
void RVCTToolChain::addToEnvironment(ProjectExplorer::Environment &env)
{
env.prependOrSetPath(QString("%1\\epoc32\\tools").arg(m_deviceRoot)); // e.g. make.exe
env.prependOrSetPath(QString("%1\\epoc32\\gcc\\bin").arg(m_deviceRoot)); // e.g. gcc.exe
env.set("EPOCDEVICE", QString("%1:%2").arg(m_deviceId, m_deviceName));
env.set("EPOCROOT", S60Devices::cleanedRootPath(m_deviceRoot));
switch (m_type) {
case ProjectExplorer::ToolChain::RVCT_ARMV6_GNUPOC:
m_mixin.addGnuPocToEnvironment(&env);
break;
default:
m_mixin.addEpocToEnvironment(&env);
break;
}
}
QString RVCTToolChain::makeCommand() const
{
return "make";
return QLatin1String("make");
}
bool RVCTToolChain::equals(ToolChain *other) const
bool RVCTToolChain::equals(ToolChain *otherIn) const
{
return (other->type() == type()
&& m_deviceId == static_cast<RVCTToolChain *>(other)->m_deviceId
&& m_deviceName == static_cast<RVCTToolChain *>(other)->m_deviceName);
if (otherIn->type() != type())
return false;
const RVCTToolChain *other = static_cast<const RVCTToolChain *>(otherIn);
return other->m_mixin == m_mixin;
}
......@@ -40,7 +40,8 @@ namespace Internal {
class RVCTToolChain : public ProjectExplorer::ToolChain
{
public:
RVCTToolChain(S60Devices::Device device, ProjectExplorer::ToolChain::ToolChainType type);
explicit RVCTToolChain(const S60Devices::Device &device,
ProjectExplorer::ToolChain::ToolChainType type);
virtual QByteArray predefinedMacros();
QList<ProjectExplorer::HeaderPath> systemHeaderPaths();
void addToEnvironment(ProjectExplorer::Environment &env);
......@@ -52,14 +53,13 @@ protected:
private:
void updateVersion();
const S60ToolChainMixin m_mixin;
const ProjectExplorer::ToolChain::ToolChainType m_type;
bool m_versionUpToDate;
int m_major;
int m_minor;
int m_build;
QString m_deviceId;
QString m_deviceName;
QString m_deviceRoot;
ProjectExplorer::ToolChain::ToolChainType m_type;
QByteArray m_predefinedMacros;
QList<ProjectExplorer::HeaderPath> m_systemHeaderPaths;
};
......
......@@ -56,6 +56,8 @@
using namespace ProjectExplorer;
using namespace Qt4ProjectManager::Internal;
enum { debug = 0 };
// Format information about a file
static QString lsFile(const QString &f)
{
......@@ -317,13 +319,18 @@ void S60DeviceRunConfiguration::updateTarget()
m_packageTemplateFileName = QDir::cleanPath(
m_workingDir + QLatin1Char('/') + m_targetName + QLatin1String("_template.pkg"));
ToolChain::ToolChainType toolchain = pro->toolChainType(pro->activeBuildConfiguration());
if (toolchain == ToolChain::GCCE)
switch (pro->toolChainType(pro->activeBuildConfiguration())) {
case ToolChain::GCCE:
case ToolChain::GCCE_GNUPOC:
m_platform = QLatin1String("gcce");
else if (toolchain == ToolChain::RVCT_ARMV5)
break;
case ToolChain::RVCT_ARMV5:
m_platform = QLatin1String("armv5");
else
break;
default: // including ToolChain::RVCT_ARMV6_GNUPOC:
m_platform = QLatin1String("armv6");
break;
}
if (projectBuildConfiguration & QtVersion::DebugBuild)
m_target = QLatin1String("udeb");
else
......@@ -396,8 +403,9 @@ QSharedPointer<RunConfiguration> S60DeviceRunConfigurationFactory::create(Projec
S60DeviceRunControlBase::S60DeviceRunControlBase(const QSharedPointer<RunConfiguration> &runConfiguration) :
RunControl(runConfiguration),
m_toolChain(ProjectExplorer::ToolChain::INVALID),
m_makesis(new QProcess(this)),
m_signsis(new QProcess(this)),
m_signsis(0),
m_launcher(0)
{
connect(m_makesis, SIGNAL(readyReadStandardError()),
......@@ -409,21 +417,12 @@ S60DeviceRunControlBase::S60DeviceRunControlBase(const QSharedPointer<RunConfigu
connect(m_makesis, SIGNAL(finished(int,QProcess::ExitStatus)),
this, SLOT(makesisProcessFinished()));
connect(m_signsis, SIGNAL(readyReadStandardError()),
this, SLOT(readStandardError()));
connect(m_signsis, SIGNAL(readyReadStandardOutput()),
this, SLOT(readStandardOutput()));
connect(m_signsis, SIGNAL(error(QProcess::ProcessError)),
this, SLOT(signsisProcessFailed()));
connect(m_signsis, SIGNAL(finished(int,QProcess::ExitStatus)),
this, SLOT(signsisProcessFinished()));
Qt4Project *project = qobject_cast<Qt4Project *>(runConfiguration->project());
QTC_ASSERT(project, return);
QSharedPointer<S60DeviceRunConfiguration> s60runConfig = runConfiguration.objectCast<S60DeviceRunConfiguration>();
QTC_ASSERT(s60runConfig, return);
m_toolChain = s60runConfig->toolChainType();
m_serialPortName = s60runConfig->serialPortName();
m_serialPortFriendlyName = S60Manager::instance()->serialDeviceLister()->friendlyNameForPort(m_serialPortName);
m_communicationType = s60runConfig->communicationType();
......@@ -437,13 +436,42 @@ S60DeviceRunControlBase::S60DeviceRunControlBase(const QSharedPointer<RunConfigu
m_useCustomSignature = (s60runConfig->signingMode() == S60DeviceRunConfiguration::SignCustom);
m_customSignaturePath = s60runConfig->customSignaturePath();
m_customKeyPath = s60runConfig->customKeyPath();
m_toolsDirectory = S60Manager::instance()->deviceForQtVersion(
project->qtVersion(project->activeBuildConfiguration())).toolsRoot
+ "/epoc32/tools";
m_executableFileName = lsFile(s60runConfig->localExecutableFileName());
m_makesisTool = m_toolsDirectory + "/makesis.exe";
ProjectExplorer::BuildConfiguration *const activeBuildConf = project->activeBuildConfiguration();
const S60Devices::Device device = S60Manager::instance()->deviceForQtVersion(project->qtVersion(activeBuildConf));
switch (m_toolChain) {
case ProjectExplorer::ToolChain::GCCE_GNUPOC:
case ProjectExplorer::ToolChain::RVCT_ARMV6_GNUPOC: {
// 'sis' is a make target here. Set up with correct environment
ProjectExplorer::ToolChain *toolchain = project->toolChain(activeBuildConf);
m_makesisTool = toolchain->makeCommand();
m_toolsDirectory = device.epocRoot + QLatin1String("/epoc32/tools");
ProjectExplorer::Environment env = ProjectExplorer::Environment::systemEnvironment();
toolchain->addToEnvironment(env);
m_makesis->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()),
this, SLOT(readStandardError()));
connect(m_signsis, SIGNAL(readyReadStandardOutput()),
this, SLOT(readStandardOutput()));
connect(m_signsis, SIGNAL(error(QProcess::ProcessError)),
this, SLOT(signsisProcessFailed()));
connect(m_signsis, SIGNAL(finished(int,QProcess::ExitStatus)),
this, SLOT(signsisProcessFinished()));
break;
}
m_executableFileName = s60runConfig->localExecutableFileName();
m_packageFilePath = s60runConfig->packageFileName();
m_packageFile = QFileInfo(m_packageFilePath).fileName();
if (debug)
qDebug() << "S60DeviceRunControlBase" << m_targetName << ProjectExplorer::ToolChain::toolChainName(m_toolChain)
<< m_serialPortName << m_communicationType << m_workingDirectory;
}
S60DeviceRunControlBase::~S60DeviceRunControlBase()
......@@ -464,7 +492,7 @@ void S60DeviceRunControlBase::start()
}
emit addToOutputWindow(this, tr("Creating %1.sisx ...").arg(QDir::toNativeSeparators(m_baseFileName)));
emit addToOutputWindow(this, tr("Executable file: %1").arg(m_executableFileName));
emit addToOutputWindow(this, tr("Executable file: %1").arg(lsFile(m_executableFileName)));
QString errorMessage;
QString settingsCategory;
......@@ -478,14 +506,27 @@ void S60DeviceRunControlBase::start()
return;
}
if (!createPackageFileFromTemplate(&errorMessage)) {
error(this, errorMessage);
emit finished();
return;
QStringList makeSisArgs;
switch (m_toolChain) {
case ProjectExplorer::ToolChain::GCCE_GNUPOC:
case ProjectExplorer::ToolChain::RVCT_ARMV6_GNUPOC:
makeSisArgs.push_back(QLatin1String("sis"));
break;
default:
makeSisArgs.push_back(m_packageFile);
if (!createPackageFileFromTemplate(&errorMessage)) {
error(this, errorMessage);
emit finished();
return;
}
break;
}
m_makesis->setWorkingDirectory(m_workingDirectory);
emit addToOutputWindow(this, tr("%1 %2").arg(QDir::toNativeSeparators(m_makesisTool), m_packageFile));
m_makesis->start(m_makesisTool, QStringList(m_packageFile), QIODevice::ReadOnly);
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);
}
static inline void stopProcess(QProcess *p)
......@@ -551,7 +592,7 @@ bool S60DeviceRunControlBase::createPackageFileFromTemplate(QString *errorMessag
void S60DeviceRunControlBase::makesisProcessFailed()
{
processFailed("makesis.exe", m_makesis->error());
processFailed(m_makesisTool, m_makesis->error());
}
void S60DeviceRunControlBase::makesisProcessFinished()
......@@ -562,6 +603,19 @@ void S60DeviceRunControlBase::makesisProcessFinished()
emit finished();
return;
}
switch (m_toolChain) {
case ProjectExplorer::ToolChain::GCCE_GNUPOC:
case ProjectExplorer::ToolChain::RVCT_ARMV6_GNUPOC:
startDeployment();
break;
default:
startSigning();
break;
}
}
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();
......@@ -589,8 +643,13 @@ void S60DeviceRunControlBase::signsisProcessFinished()
error(this, tr("An error occurred while creating the package."));
stop();
emit finished();
return;
} else {
startDeployment();
}
}
void S60DeviceRunControlBase::startDeployment()
{
m_launcher = new trk::Launcher();
connect(m_launcher, SIGNAL(finished()), this, SLOT(launcherFinished()));
connect(m_launcher, SIGNAL(canNotConnect(QString)), this, SLOT(printConnectFailed(QString)));
......
......@@ -127,8 +127,11 @@ public:
QSharedPointer<ProjectExplorer::RunConfiguration> create(ProjectExplorer::Project *project, const QString &type);
};
/* S60DeviceRunControlBase: Builds and signs package and starts launcher
* to deploy. Subclasses can configure the launcher to run or start a debugger. */
/* 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'
* Other: run the makesis.exe tool, run signsis */
class S60DeviceRunControlBase : public ProjectExplorer::RunControl
{
......@@ -175,7 +178,10 @@ private slots:
private:
bool createPackageFileFromTemplate(QString *errorMessage);
void startSigning();
void startDeployment();
ProjectExplorer::ToolChain::ToolChainType m_toolChain;
QString m_serialPortName;
QString m_serialPortFriendlyName;
int m_communicationType;
......
......@@ -28,6 +28,9 @@
**************************************************************************/
#include "s60devices.h"
#include "gccetoolchain.h"
#include <projectexplorer/environment.h>
#include <QtCore/QSettings>
#include <QtCore/QXmlStreamReader>
......@@ -81,10 +84,47 @@ S60Devices::S60Devices(QObject *parent)
{
}
// GNU-Poc stuff
static const char *gnuPocRootC = "GNUPOC_ROOT";
static inline QString msgEnvVarNotSet(const char *var)
{
return QString::fromLatin1("The environment variable %1 is not set.").arg(QLatin1String(var));
}
static inline QString msgEnvVarDirNotExist(const QString &dir, const char *var)
{
return QString::fromLatin1("The directory %1 pointed to by the environment variable %2 is not set.").arg(dir, QLatin1String(var));
}
bool S60Devices::readLinux()
{
m_errorString = QLatin1String("not implemented.");
return false;
// Detect GNUPOC_ROOT/EPOC ROOT
const QByteArray gnuPocRootA = qgetenv(gnuPocRootC);
if (gnuPocRootA.isEmpty()) {
m_errorString = msgEnvVarNotSet(gnuPocRootC);
return false;
}
const QDir gnuPocRootDir(QString::fromLocal8Bit(gnuPocRootA));
if (!gnuPocRootDir.exists()) {
m_errorString = msgEnvVarDirNotExist(gnuPocRootDir.absolutePath(), gnuPocRootC);
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.isDefault = true;
m_devices.push_back(device);
return true;
}
bool S60Devices::read()
......@@ -162,6 +202,8 @@ bool S60Devices::readWin()
bool S60Devices::detectQtForDevices()
{
for (int i = 0; i < m_devices.size(); ++i) {
if (!m_devices[i].qt.isEmpty())
continue;
QFile qtDll(QString("%1/epoc32/release/winscw/udeb/QtCore.dll").arg(m_devices[i].epocRoot));
if (!qtDll.exists() || !qtDll.open(QIODevice::ReadOnly)) {
m_devices[i].qt = QString();
......@@ -237,6 +279,57 @@ QString S60Devices::cleanedRootPath(const QString &deviceRoot)
return path;
}
// S60ToolChainMixin
S60ToolChainMixin::S60ToolChainMixin(const S60Devices::Device &d) :
m_device(d)
{
}
const S60Devices::Device & S60ToolChainMixin::device() const
{
return m_device;
}
bool S60ToolChainMixin::equals(const S60ToolChainMixin &rhs) const
{
return m_device.id == rhs.m_device.id
&& m_device.name == rhs.m_device.name;
}
QList<ProjectExplorer::HeaderPath> S60ToolChainMixin::epocHeaderPaths() const