qmake/generators/symbian/symmake.cpp
changeset 7 f7bc934e204c
parent 3 41300fa6a67c
--- a/qmake/generators/symbian/symmake.cpp	Tue Feb 02 00:43:10 2010 +0200
+++ b/qmake/generators/symbian/symmake.cpp	Wed Mar 31 11:06:36 2010 +0300
@@ -1,6 +1,6 @@
 /****************************************************************************
 **
-** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
 ** All rights reserved.
 ** Contact: Nokia Corporation (qt-info@nokia.com)
 **
@@ -40,7 +40,6 @@
 ****************************************************************************/
 
 #include "symmake.h"
-#include "initprojectdeploy_symbian.h"
 
 #include <qstring.h>
 #include <qhash.h>
@@ -50,25 +49,34 @@
 #include <stdlib.h>
 #include <qdebug.h>
 #include <qxmlstream.h>
-#include <qsettings>
+#include <QSettings>
+
+// Included from tools/shared
+#include <symbian/epocroot.h>
 
 #define RESOURCE_DIRECTORY_MMP "/resource/apps"
 #define RESOURCE_DIRECTORY_RESOURCE "\\\\resource\\\\apps\\\\"
 #define REGISTRATION_RESOURCE_DIRECTORY_HW "/private/10003a3f/import/apps"
 #define PLUGIN_COMMON_DEF_FILE_FOR_MMP "./plugin_common.def"
 #define PLUGIN_COMMON_DEF_FILE_ACTUAL "plugin_commonU.def"
-#define BLD_INF_FILENAME_LEN (sizeof(BLD_INF_FILENAME) - 1)
 
 #define BLD_INF_RULES_BASE "BLD_INF_RULES."
 #define BLD_INF_TAG_PLATFORMS "prj_platforms"
 #define BLD_INF_TAG_MMPFILES "prj_mmpfiles"
 #define BLD_INF_TAG_TESTMMPFILES "prj_testmmpfiles"
 #define BLD_INF_TAG_EXTENSIONS "prj_extensions"
+#define BLD_INF_TAG_TESTEXTENSIONS "prj_testextensions"
 
 #define RSS_RULES "RSS_RULES"
 #define RSS_RULES_BASE "RSS_RULES."
 #define RSS_TAG_NBROFICONS "number_of_icons"
 #define RSS_TAG_ICONFILE "icon_file"
+#define RSS_TAG_HEADER "header"
+#define RSS_TAG_SERVICE_LIST "service_list"
+#define RSS_TAG_FILE_OWNERSHIP_LIST "file_ownership_list"
+#define RSS_TAG_DATATYPE_LIST "datatype_list"
+#define RSS_TAG_FOOTER "footer"
+#define RSS_TAG_DEFAULT "default_rules" // Same as just giving rules without tag
 
 #define MMP_TARGET "TARGET"
 #define MMP_TARGETTYPE "TARGETTYPE"
@@ -90,22 +98,32 @@
 #define MMP_END_RESOURCE "END"
 
 #define SIS_TARGET "sis"
+#define INSTALLER_SIS_TARGET "installer_sis"
+#define ROM_STUB_SIS_TARGET "stub_sis"
 #define OK_SIS_TARGET "ok_sis"
+#define OK_INSTALLER_SIS_TARGET "ok_installer_sis"
+#define OK_ROM_STUB_SIS_TARGET "ok_stub_sis"
 #define FAIL_SIS_NOPKG_TARGET "fail_sis_nopkg"
 #define FAIL_SIS_NOCACHE_TARGET "fail_sis_nocache"
-#define RESTORE_BUILD_TARGET "restore_build"
 
 #define PRINT_FILE_CREATE_ERROR(filename) fprintf(stderr, "Error: Could not create '%s'\n", qPrintable(filename));
 
+#define MANUFACTURER_NOTE_FILE "manufacturer_note.txt"
+#define DEFAULT_MANUFACTURER_NOTE \
+    "The package is not supported for devices from this manufacturer. Please try the selfsigned " \
+    "version of the package instead."
+
 QString SymbianMakefileGenerator::fixPathForMmp(const QString& origPath, const QDir& parentDir)
 {
     static QString epocRootStr;
     if (epocRootStr.isEmpty()) {
-        QFileInfo efi(epocRoot());
-        epocRootStr = efi.canonicalFilePath();
-        if (epocRootStr.isEmpty()) {
+        epocRootStr = epocRoot();
+        QFileInfo efi(epocRootStr);
+        if (!efi.exists() || epocRootStr.isEmpty()) {
             fprintf(stderr, "Unable to resolve epocRoot '%s' to real dir on current drive, defaulting to '/' for mmp paths\n", qPrintable(epocRoot()));
             epocRootStr = "/";
+        } else {
+            epocRootStr = efi.absoluteFilePath();
         }
         if (!epocRootStr.endsWith("/"))
             epocRootStr += "/";
@@ -129,53 +147,26 @@
     return resultPath;
 }
 
-QString SymbianMakefileGenerator::canonizePath(const QString& origPath)
+QString SymbianMakefileGenerator::absolutizePath(const QString& origPath)
 {
-    // Since current path gets appended almost always anyway, use it as default
-    // for nonexisting paths.
-    static QString defaultPath;
-    if (defaultPath.isEmpty()) {
-        QFileInfo fi(".");
-        defaultPath = fi.canonicalFilePath();
-    }
-
     // Prepend epocroot to any paths beginning with "/epoc32/"
     QString resultPath = QDir::fromNativeSeparators(origPath);
-    QString tempPath(resultPath);
-    bool isEpoc = false;
-    if (resultPath.startsWith("/epoc32/", Qt::CaseInsensitive)) {
-        isEpoc = true;
+    if (resultPath.startsWith("/epoc32/", Qt::CaseInsensitive))
         resultPath = QDir::fromNativeSeparators(epocRoot()) + resultPath.mid(1);
-    }
 
     QFileInfo fi(fileInfo(resultPath));
-    if(fi.isDir()) {
-        if (isEpoc)
-            resultPath = fi.absoluteFilePath();//canonicalFilePath();
-        else
-            resultPath = fi.canonicalFilePath();            
+
+    // Since origPath can be something given in HEADERS, we need to check if we are dealing
+    // with a file or a directory. In case the origPath doesn't yet exist, isFile() returns
+    // false and we default to assuming it is a dir.
+    if (fi.isFile()) {
+        resultPath = fi.absolutePath();
     } else {
-        if (isEpoc)
-            resultPath = fi.absolutePath();//canonicalPath();
-        else
-            resultPath = fi.canonicalPath();
-    }
-    //some fix for the not existed EPOC32\include folder
-    if (isEpoc) {
-        int index = resultPath.lastIndexOf("/epoc32/"); 
-        QString tmpRes = resultPath.mid(index);
-        if (tmpRes != tempPath) {
-            //we have the problems for not existed include directory
-            //change the path
-            resultPath.replace(tmpRes, tempPath);
-            }
+        resultPath = fi.absoluteFilePath();
     }
 
     resultPath = QDir::cleanPath(resultPath);
 
-    if (resultPath.isEmpty())
-        resultPath = defaultPath;
-
     return resultPath;
 }
 
@@ -217,7 +208,7 @@
 
     QString numberOfIcons;
     QString iconFile;
-    QStringList userRssRules;
+    QMap<QString, QStringList> userRssRules;
     readRssRules(numberOfIcons, iconFile, userRssRules);
 
     // Get the application translations and convert to symbian OS lang code, i.e. decical number
@@ -225,6 +216,8 @@
 
     // Generate pkg files if there are any actual files to deploy
     bool generatePkg = false;
+    DeploymentList depList;
+
     if (targetType == TypeExe) {
         generatePkg = true;
     } else {
@@ -237,10 +230,10 @@
     }
 
     if (generatePkg) {
-        generatePkgFile(iconFile);
+        generatePkgFile(iconFile, depList);
     }
 
-    writeBldInfContent(t, generatePkg, iconFile);
+    writeBldInfContent(t, generatePkg, iconFile, depList);
 
     // Generate empty wrapper makefile here, because wrapper makefile must exist before writeMkFile,
     // but all required data is not yet available.
@@ -248,7 +241,9 @@
     QString wrapperFileName("Makefile");
     QString outputFileName = fileInfo(Option::output.fileName()).fileName();
     if (outputFileName != BLD_INF_FILENAME) {
-        wrapperFileName.append(".").append((outputFileName.size() > BLD_INF_FILENAME_LEN && outputFileName.left(BLD_INF_FILENAME_LEN) == BLD_INF_FILENAME) ? outputFileName.mid(8) : outputFileName);
+        wrapperFileName.append(".").append(outputFileName.startsWith(BLD_INF_FILENAME)
+                                           ? outputFileName.mid(sizeof(BLD_INF_FILENAME))
+                                           : outputFileName);
         isPrimaryMakefile = false;
     }
 
@@ -286,7 +281,7 @@
     writeMmpFile(mmpFilename, symbianLangCodes);
 
     if (targetType == TypeExe) {
-        if (!project->values("CONFIG").contains("no_icon", Qt::CaseInsensitive)) {
+        if (!project->isActiveConfig("no_icon")) {
             writeRegRssFile(userRssRules);
             writeRssFile(numberOfIcons, iconFile);
             writeLocFile(symbianLangCodes);
@@ -301,7 +296,7 @@
     return true;
 }
 
-void SymbianMakefileGenerator::generatePkgFile(const QString &iconFile)
+void SymbianMakefileGenerator::generatePkgFile(const QString &iconFile, DeploymentList &depList)
 {
     QString pkgFilename = QString("%1_template.%2")
                           .arg(fixedTarget)
@@ -315,25 +310,58 @@
         generatePrint(fileInfo(pkgFile.fileName()).absoluteFilePath());
     }
     generatedFiles << pkgFile.fileName();
+    QTextStream t(&pkgFile);
+
+    QString installerSisHeader = project->values("DEPLOYMENT.installer_header").join("\n");
+    if (installerSisHeader.isEmpty())
+        installerSisHeader = "0xA000D7CE"; // Use default self-signable UID if not defined
+
+    QString wrapperStreamBuffer;
+    QTextStream tw(&wrapperStreamBuffer);
+
+    QString dateStr = QDateTime::currentDateTime().toString(Qt::ISODate);
 
     // Header info
-    QTextStream t(&pkgFile);
-    t << QString("; %1 generated by qmake at %2").arg(pkgFilename).arg(QDateTime::currentDateTime().toString(Qt::ISODate))  << endl;
-    t << "; This file is generated by qmake and should not be modified by the user" << endl;
-    t << ";" << endl << endl;
+    QString wrapperPkgFilename = QString("%1_installer.%2")
+                                .arg(fixedTarget)
+                                .arg("pkg");
+    QString headerComment = "; %1 generated by qmake at %2\n"
+        "; This file is generated by qmake and should not be modified by the user\n"
+        ";\n\n";
+    t << headerComment.arg(pkgFilename).arg(dateStr);
+    tw << headerComment.arg(wrapperPkgFilename).arg(dateStr);
 
     // Construct QStringList from pkg_prerules since we need search it before printed to file
+    // Note: Though there can't be more than one language or header line, use stringlists
+    // in case user wants comments to go with the rules.
     QStringList rawPkgPreRules;
+    QStringList languageRules;
+    QStringList headerRules;
     foreach(QString deploymentItem, project->values("DEPLOYMENT")) {
         foreach(QString pkgrulesItem, project->values(deploymentItem + ".pkg_prerules")) {
             QStringList pkgrulesValue = project->values(pkgrulesItem);
             // If there is no stringlist defined for a rule, use rule name directly
             // This is convenience for defining single line mmp statements
             if (pkgrulesValue.isEmpty()) {
-                rawPkgPreRules << pkgrulesItem;
+                if (pkgrulesItem.startsWith("&"))
+                    languageRules << pkgrulesItem;
+                else if (pkgrulesItem.startsWith("#"))
+                    headerRules << pkgrulesItem;
+                else
+                    rawPkgPreRules << pkgrulesItem;
             } else {
-                foreach(QString pkgrule, pkgrulesValue) {
-                    rawPkgPreRules << pkgrule;
+                if (containsStartWithItem('&', pkgrulesValue)) {
+                    foreach(QString pkgrule, pkgrulesValue) {
+                        languageRules << pkgrule;
+                    }
+                } else if (containsStartWithItem('#', pkgrulesValue)) {
+                    foreach(QString pkgrule, pkgrulesValue) {
+                        headerRules << pkgrule;
+                    }
+                } else {
+                    foreach(QString pkgrule, pkgrulesValue) {
+                        rawPkgPreRules << pkgrule;
+                    }
                 }
             }
         }
@@ -341,46 +369,76 @@
 
     // Apply some defaults if specific data does not exist in PKG pre-rules
 
-    if (!containsStartWithItem('&', rawPkgPreRules)) {
+    if (languageRules.isEmpty()) {
         // language, (*** hardcoded to english atm, should be parsed from TRANSLATIONS)
-        t << "; Language" << endl;
-        t << "&EN" << endl << endl;
-    } else {
+        languageRules << "; Language\n&EN\n\n";
+    } else if (headerRules.isEmpty()) {
         // In case user defines langs, he must take care also about SIS header
-        if (!containsStartWithItem('#', rawPkgPreRules))
-            fprintf(stderr, "Warning: If language is defined with DEPLOYMENT pkg_prerules, also the SIS header must be defined\n");
+        fprintf(stderr, "Warning: If language is defined with DEPLOYMENT pkg_prerules, also the SIS header must be defined\n");
     }
 
+    t << languageRules.join("\n") << endl;
+    tw << languageRules.join("\n") << endl;
+
     // name of application, UID and version
     QString applicationVersion = project->first("VERSION").isEmpty() ? "1,0,0" : project->first("VERSION").replace('.', ',');
+    QString sisHeader = "; SIS header: name, uid, version\n#{\"%1\"},(%2),%3\n\n";
+    QString visualTarget = escapeFilePath(fileFixify(project->first("TARGET")));
+    visualTarget = removePathSeparators(visualTarget);
+    QString wrapperTarget = visualTarget + " installer";
 
-    if (!containsStartWithItem('#', rawPkgPreRules)) {
-        QString visualTarget = escapeFilePath(fileFixify(project->first("TARGET")));
-        visualTarget = removePathSeparators(visualTarget);
-
-        t << "; SIS header: name, uid, version" << endl;
-        t << QString("#{\"%1\"},(%2),%3").arg(visualTarget).arg(uid3).arg(applicationVersion) << endl << endl;
+    if (installerSisHeader.startsWith("0x", Qt::CaseInsensitive)) {
+        tw << sisHeader.arg(wrapperTarget).arg(installerSisHeader).arg(applicationVersion);
+    } else {
+        tw << installerSisHeader << endl;
     }
 
+    if (headerRules.isEmpty())
+        t << sisHeader.arg(visualTarget).arg(uid3).arg(applicationVersion);
+    else
+        t << headerRules.join("\n") << endl;
+
     // Localized vendor name
+    QString vendorName;
     if (!containsStartWithItem('%', rawPkgPreRules)) {
-        t << "; Localised Vendor name" << endl;
-        t << "%{\"Vendor\"}" << endl << endl;
+        vendorName += "; Localised Vendor name\n%{\"Vendor\"}\n\n";
     }
 
     // Unique vendor name
     if (!containsStartWithItem(':', rawPkgPreRules)) {
-        t << "; Unique Vendor name" << endl;
-        t << ":\"Vendor\"" << endl << endl;
+        vendorName += "; Unique Vendor name\n:\"Vendor\"\n\n";
     }
 
+    t << vendorName;
+    tw << vendorName;
+
     // PKG pre-rules - these are added before actual file installations i.e. SIS package body
     if (rawPkgPreRules.size()) {
-        t << "; Manual PKG pre-rules from PRO files" << endl;
+        QString comment = "\n; Manual PKG pre-rules from PRO files\n";
+        t << comment;
+        tw << comment;
+
         foreach(QString item, rawPkgPreRules) {
+            // Only regular pkg file should have package dependencies or pkg header if that is
+            // defined using prerules.
+            if (!item.startsWith("(") && !item.startsWith("#")) {
+                tw << item << endl;
+            }
             t << item << endl;
         }
         t << endl;
+        tw << endl;
+    }
+
+    // Begin Manufacturer block
+    if (!project->values("DEPLOYMENT.manufacturers").isEmpty()) {
+        QString manufacturerStr("IF ");
+        foreach(QString manufacturer, project->values("DEPLOYMENT.manufacturers")) {
+            manufacturerStr.append(QString("(MANUFACTURER)=(%1) OR \n   ").arg(manufacturer));
+        }
+        // Remove the final OR
+        manufacturerStr.chop(8);
+        t << manufacturerStr << endl;
     }
 
     // Install paths on the phone *** should be dynamic at some point
@@ -392,7 +450,6 @@
     QString epocReleasePath = QString("%1epoc32/release/$(PLATFORM)/$(TARGET)")
                               .arg(epocRoot());
 
-
     if (targetType == TypeExe) {
         // deploy .exe file
         t << "; Executable and default resource files" << endl;
@@ -404,7 +461,7 @@
              .arg(exeFile) << endl;
 
         // deploy rsc & reg_rsc file
-        if (!project->values("CONFIG").contains("no_icon", Qt::CaseInsensitive)) {
+        if (!project->isActiveConfig("no_icon")) {
             t << QString("\"%1epoc32/data/z/resource/apps/%2\"    - \"%3\\%4\"")
                  .arg(epocRoot())
                  .arg(fixedTarget + ".rsc")
@@ -427,17 +484,31 @@
     }
 
     // deploy any additional DEPLOYMENT  files
-    DeploymentList depList;
     QString remoteTestPath;
     remoteTestPath = QString("!:\\private\\%1").arg(privateDirUid);
+    QString zDir = epocRoot() + QLatin1String("epoc32/data/z");
 
     initProjectDeploySymbian(project, depList, remoteTestPath, true, "$(PLATFORM)", "$(TARGET)", generatedDirs, generatedFiles);
     if (depList.size())
         t << "; DEPLOYMENT" << endl;
     for (int i = 0; i < depList.size(); ++i)  {
-        t << QString("\"%1\"    - \"%2\"")
-             .arg(QString(depList.at(i).from).replace('\\','/'))
-             .arg(depList.at(i).to) << endl;
+        QString from = depList.at(i).from;
+        QString to = depList.at(i).to;
+
+        // Deploy anything not already deployed from under epoc32 instead from under
+        // \epoc32\data\z\ to enable using pkg file without rebuilding
+        // the project, which can be useful for some binary only distributions.
+        if (!from.contains(QLatin1String("epoc32"), Qt::CaseInsensitive)) {
+            from = to;
+            if (from.size() > 1 && from.at(1) == QLatin1Char(':'))
+                from = from.mid(2);
+            from.prepend(zDir);
+        } else {
+            if (from.size() > 1 && from.at(1) == QLatin1Char(':'))
+                from = from.mid(2);
+        }
+
+        t << QString("\"%1\"    - \"%2\"").arg(from.replace('\\','/')).arg(to) << endl;
     }
     t << endl;
 
@@ -458,6 +529,54 @@
             t << endl;
         }
     }
+
+    // Close Manufacturer block
+    if (!project->values("DEPLOYMENT.manufacturers").isEmpty()) {
+        QString manufacturerFailNoteFile;
+        if (project->values("DEPLOYMENT.manufacturers.fail_note").isEmpty()) {
+            manufacturerFailNoteFile = QString("%1_" MANUFACTURER_NOTE_FILE).arg(uid3);
+            QFile ft(manufacturerFailNoteFile);
+            if (ft.open(QIODevice::WriteOnly)) {
+                generatedFiles << ft.fileName();
+                QTextStream t2(&ft);
+
+                t2 << QString(DEFAULT_MANUFACTURER_NOTE) << endl;
+            } else {
+                PRINT_FILE_CREATE_ERROR(manufacturerFailNoteFile)
+            }
+        } else {
+            manufacturerFailNoteFile = project->values("DEPLOYMENT.manufacturers.fail_note").join("");
+        }
+
+        t << "ELSEIF NOT(0) ; MANUFACTURER" << endl
+          << "\"" << fileInfo(manufacturerFailNoteFile).absoluteFilePath() << "\""
+          << " - \"\", FILETEXT, TEXTEXIT" << endl
+          << "ENDIF ; MANUFACTURER" << endl;
+    }
+
+    // Write wrapper pkg
+    if (!installerSisHeader.isEmpty()) {
+        QFile wrapperPkgFile(wrapperPkgFilename);
+        if (!wrapperPkgFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
+            PRINT_FILE_CREATE_ERROR(wrapperPkgFilename);
+            return;
+        }
+
+        generatedFiles << wrapperPkgFile.fileName();
+        QTextStream twf(&wrapperPkgFile);
+
+        twf << wrapperStreamBuffer << endl;
+
+        // Wrapped files deployment
+        QString currentPath = qmake_getpwd();
+        QString sisName = QString("%1.sis").arg(fixedTarget);
+        twf << "\"" << currentPath << "/" << sisName << "\" - \"c:\\adm\\" << sisName << "\"" << endl;
+
+        QString bootStrapPath = QLibraryInfo::location(QLibraryInfo::PrefixPath);
+        bootStrapPath.append("/smartinstaller.sis");
+        QFileInfo fi(fileInfo(bootStrapPath));
+        twf << "@\"" << fi.absoluteFilePath() << "\",(0x2002CCCD)" << endl;
+    }
 }
 
 bool SymbianMakefileGenerator::containsStartWithItem(const QChar &c, const QStringList& src)
@@ -474,7 +593,7 @@
 
 void SymbianMakefileGenerator::writeCustomDefFile()
 {
-    if (targetType == TypePlugin && !project->values("CONFIG").contains("stdbinary", Qt::CaseInsensitive)) {
+    if (targetType == TypePlugin && !project->isActiveConfig("stdbinary")) {
         // Create custom def file for plugin
         QFile ft(QLatin1String(PLUGIN_COMMON_DEF_FILE_ACTUAL));
 
@@ -515,6 +634,15 @@
     fixedTarget = escapeFilePath(fileFixify(project->first("TARGET")));
     fixedTarget = removePathSeparators(fixedTarget);
     removeSpecialCharacters(fixedTarget);
+    
+ 		translationFileName = escapeFilePath(fileFixify(project->first("TRANSLATIONS")));
+ 		if (!translationFileName.isEmpty()){
+ 		 		translationFileName.chop(3);
+ 				translationFileName = removePathSeparators(translationFileName);
+ 				removeSpecialCharacters(translationFileName);
+ 			}
+ 			else
+ 				translationFileName = fixedTarget;
 
     if (0 != project->values("QMAKE_PLATFORM").size())
         platform = varGlue("QMAKE_PLATFORM", "", " ", "");
@@ -542,9 +670,9 @@
         targetType = TypeExe;
     else if ((project->values("TEMPLATE")).contains("lib")) {
         // Check CONFIG to see if we are to build staticlib or dll
-        if (project->values("CONFIG").contains("staticlib") || project->values("CONFIG").contains("static"))
+        if (project->isActiveConfig("staticlib") || project->isActiveConfig("static"))
             targetType = TypeLib;
-        else if (project->values("CONFIG").contains("plugin"))
+        else if (project->isActiveConfig("plugin"))
             targetType = TypePlugin;
         else
             targetType = TypeDll;
@@ -554,7 +682,7 @@
 
     if (0 != project->values("TARGET.UID2").size()) {
         uid2 = project->first("TARGET.UID2");
-    } else if (project->values("CONFIG").contains("stdbinary", Qt::CaseInsensitive)) {
+    } else if (project->isActiveConfig("stdbinary")) {
         uid2 = "0x20004C45";
     } else {
         if (targetType == TypeExe) {
@@ -625,7 +753,7 @@
     srcpaths << project->values("UI_DIR");
 
     QDir current = QDir::current();
-    QString canonizedCurrent = canonizePath(".");
+    QString absolutizedCurrent = absolutizePath(".");
 
     for (int j = 0; j < srcpaths.size(); ++j) {
         QFileInfo fi(fileInfo(srcpaths.at(j)));
@@ -633,10 +761,10 @@
         if (fi.suffix().startsWith("c")) {
             if (fi.filePath().length() > fi.fileName().length()) {
                 appendIfnotExist(srcincpaths, fi.path());
-                sources[canonizePath(fi.path())] += fi.fileName();
+                sources[absolutizePath(fi.path())] += fi.fileName();
             } else {
-                sources[canonizedCurrent] += fi.fileName();
-                appendIfnotExist(srcincpaths, canonizedCurrent);
+                sources[absolutizedCurrent] += fi.fileName();
+                appendIfnotExist(srcincpaths, absolutizedCurrent);
             }
         }
     }
@@ -650,7 +778,7 @@
     incpaths << project->values("UI_DIR");
 
     for (int j = 0; j < incpaths.size(); ++j) {
-        QString includepath = canonizePath(incpaths.at(j));
+        QString includepath = absolutizePath(incpaths.at(j));
         appendIfnotExist(sysincspaths, includepath);
         appendAbldTempDirs(sysincspaths, includepath);
     }
@@ -692,15 +820,13 @@
     QStringList restrictedMmpKeywords;
     bool inResourceBlock = false;
 
-    overridableMmpKeywords << QLatin1String(MMP_TARGETTYPE);
+    overridableMmpKeywords << QLatin1String(MMP_TARGETTYPE) << QLatin1String(MMP_EPOCHEAPSIZE);
     restrictableMmpKeywords << QLatin1String(MMP_TARGET) << QLatin1String(MMP_SECUREID)
-       << QLatin1String(MMP_OPTION_CW) << QLatin1String(MMP_OPTION_ARMCC)
-       << QLatin1String(MMP_OPTION_GCCE) << QLatin1String(MMP_LINKEROPTION_CW)
-       << QLatin1String(MMP_LINKEROPTION_ARMCC) << QLatin1String(MMP_LINKEROPTION_GCCE)
+       << QLatin1String(MMP_LINKEROPTION_CW) << QLatin1String(MMP_LINKEROPTION_ARMCC)
+       << QLatin1String(MMP_LINKEROPTION_GCCE)
        << QLatin1String(MMP_CAPABILITY) << QLatin1String(MMP_EPOCALLOWDLLDATA)
-       << QLatin1String(MMP_EPOCHEAPSIZE) << QLatin1String(MMP_EPOCSTACKSIZE)
-       << QLatin1String(MMP_UID) << QLatin1String(MMP_VENDORID)
-       << QLatin1String(MMP_VERSION);
+       << QLatin1String(MMP_EPOCSTACKSIZE) << QLatin1String(MMP_UID)
+       << QLatin1String(MMP_VENDORID) << QLatin1String(MMP_VERSION);
 
     foreach (QString item, project->values("MMP_RULES")) {
         if (project->values(item).isEmpty()) {
@@ -825,7 +951,7 @@
         }
         t << endl;
 
-        if (!project->values("CONFIG").contains("static") && !project->values("CONFIG").contains("staticlib")) {
+        if (!project->isActiveConfig("static") && !project->isActiveConfig("staticlib")) {
             writeMmpFileLibraryPart(t);
         }
 
@@ -874,11 +1000,12 @@
 void SymbianMakefileGenerator::writeMmpFileTargetPart(QTextStream& t)
 {
     bool skipTargetType = overriddenMmpKeywords.contains(MMP_TARGETTYPE);
+    bool skipEpocHeapSize = overriddenMmpKeywords.contains(MMP_EPOCHEAPSIZE);
 
     if (targetType == TypeExe) {
         t << MMP_TARGET "\t\t" << fixedTarget << ".exe" << endl;
         if (!skipTargetType) {
-            if (project->values("CONFIG").contains("stdbinary", Qt::CaseInsensitive))
+            if (project->isActiveConfig("stdbinary"))
                 t << MMP_TARGETTYPE "\t\tSTDEXE" << endl;
             else
                 t << MMP_TARGETTYPE "\t\tEXE" << endl;
@@ -886,7 +1013,7 @@
     } else if (targetType == TypeDll || targetType == TypePlugin) {
         t << MMP_TARGET "\t\t" << fixedTarget << ".dll" << endl;
         if (!skipTargetType) {
-            if (project->values("CONFIG").contains("stdbinary", Qt::CaseInsensitive))
+            if (project->isActiveConfig("stdbinary"))
                 t << MMP_TARGETTYPE "\t\tSTDDLL" << endl;
             else
                 t << MMP_TARGETTYPE "\t\tDLL" << endl;
@@ -894,7 +1021,7 @@
     } else if (targetType == TypeLib) {
         t << MMP_TARGET "\t\t" << fixedTarget << ".lib" << endl;
         if (!skipTargetType) {
-            if (project->values("CONFIG").contains("stdbinary", Qt::CaseInsensitive))
+            if (project->isActiveConfig("stdbinary"))
                 t << MMP_TARGETTYPE "\t\tSTDLIB" << endl;
             else
                 t << MMP_TARGETTYPE "\t\tLIB" << endl;
@@ -925,12 +1052,12 @@
 
     if (0 != project->first("TARGET.EPOCSTACKSIZE").size())
         t << MMP_EPOCSTACKSIZE "\t\t" << project->first("TARGET.EPOCSTACKSIZE") << endl;
-    if (0 != project->values("TARGET.EPOCHEAPSIZE").size())
+    if (!skipEpocHeapSize && 0 != project->values("TARGET.EPOCHEAPSIZE").size())
         t << MMP_EPOCHEAPSIZE "\t\t" << project->values("TARGET.EPOCHEAPSIZE").join(" ") << endl;
     if (0 != project->values("TARGET.EPOCALLOWDLLDATA").size())
         t << MMP_EPOCALLOWDLLDATA << endl;
 
-    if (targetType == TypePlugin && !project->values("CONFIG").contains("stdbinary", Qt::CaseInsensitive)) {
+    if (targetType == TypePlugin && !project->isActiveConfig("stdbinary")) {
         // Use custom def file for Qt plugins
         t << "DEFFILE " PLUGIN_COMMON_DEF_FILE_FOR_MMP << endl;
     }
@@ -946,7 +1073,7 @@
 void SymbianMakefileGenerator::writeMmpFileResourcePart(QTextStream& t, QStringList &symbianLangCodes)
 {
     if ((targetType == TypeExe) &&
-            !project->values("CONFIG").contains("no_icon", Qt::CaseInsensitive)) {
+            !project->isActiveConfig("no_icon")) {
 
         QString locTarget = fixedTarget;
         locTarget.append(".rss");
@@ -1153,6 +1280,16 @@
         t << MMP_OPTION_CW " " << cw <<  endl;
     if (!armcc.isEmpty())
         t << MMP_OPTION_ARMCC " " << armcc <<  endl;
+
+    foreach(QString armccVersion, project->values("VERSION_FLAGS.ARMCC")) {
+        QStringList currentValues = project->values("QMAKE_CXXFLAGS." + armccVersion);
+        if (currentValues.size()) {
+            t << "#if defined(" << armccVersion << ")" << endl;
+            t << MMP_OPTION_ARMCC " " << currentValues.join(" ") <<  endl;
+            t << "#endif" << endl;
+        }
+    }
+
     if (!gcce.isEmpty())
         t << MMP_OPTION_GCCE " " << gcce <<  endl;
 
@@ -1218,7 +1355,7 @@
     }
 }
 
-void SymbianMakefileGenerator::writeBldInfContent(QTextStream &t, bool addDeploymentExtension, const QString &iconFile)
+void SymbianMakefileGenerator::writeBldInfContent(QTextStream &t, bool addDeploymentExtension, const QString &iconFile, DeploymentList &depList)
 {
     // Read user defined bld inf rules
 
@@ -1265,6 +1402,10 @@
             fixedItem = item;
         }
 
+        QString condition;
+        if (!project->isEmpty(item + ".condition"))
+            condition = project->first(item + ".condition");
+
         QFileInfo subdir(fileInfo(fixedItem));
         QString relativePath = directory.relativeFilePath(fixedItem);
         QString subdirFileName = subdir.completeBaseName();
@@ -1293,9 +1434,16 @@
         bldinfDefine = bldinfDefine.toUpper();
         removeSpecialCharacters(bldinfDefine);
 
+        if (!condition.isEmpty())
+            t << "#if defined(" << condition << ")" << endl;
+
         t << "#ifndef " << bldinfDefine << endl;
-        t << "\t#include \"" << QDir::toNativeSeparators(bldinfFilename) << "\"" << endl;
-        t << "#endif // " << bldinfDefine << endl;
+        t << "\t#include \"" << bldinfFilename << "\"" << endl;
+        t << "#endif" << endl;
+
+        if (!condition.isEmpty())
+            t << "#endif" << endl;
+
     }
 
     // Add supported project platforms
@@ -1313,7 +1461,7 @@
     // Add project mmps and old style extension makefiles
 
     QString mmpTag;
-    if (project->values("CONFIG").contains("symbian_test", Qt::CaseInsensitive))
+    if (project->isActiveConfig(SYMBIAN_TEST_CONFIG))
         mmpTag = QLatin1String(BLD_INF_TAG_TESTMMPFILES);
     else
         mmpTag = QLatin1String(BLD_INF_TAG_MMPFILES);
@@ -1336,16 +1484,22 @@
         t << item << endl;
     userBldInfRules.remove(mmpTag);
 
-    t << endl << BLD_INF_TAG_EXTENSIONS << endl << endl;
+    QString extensionTag;
+    if (project->isActiveConfig(SYMBIAN_TEST_CONFIG))
+        extensionTag = QLatin1String(BLD_INF_TAG_TESTEXTENSIONS);
+    else
+        extensionTag = QLatin1String(BLD_INF_TAG_EXTENSIONS);
+
+    t << endl << extensionTag << endl << endl;
 
     // Generate extension rules
 
     writeBldInfExtensionRulesPart(t, iconFile);
 
-    userItems = userBldInfRules.value(BLD_INF_TAG_EXTENSIONS);
+    userItems = userBldInfRules.value(extensionTag);
     foreach(QString item, userItems)
         t << item << endl;
-    userBldInfRules.remove(BLD_INF_TAG_EXTENSIONS);
+    userBldInfRules.remove(extensionTag);
 
     // Add rest of the user defined content
 
@@ -1355,80 +1509,9 @@
         foreach(QString item, userItems)
             t << item << endl;
     }
-    if (project->values("CONFIG").contains("headerexport", Qt::CaseInsensitive)) {
-        writeExportPart(t);
-    }
 }
 
-void SymbianMakefileGenerator::writeExportPart(QTextStream &t)
-{
-    QDir currentDir = QDir::current();
-    t << "prj_exports" << endl;
-
-    foreach(QString install, project->values("INSTALLS")) {
-        QString installDir = project->first(install + ".path");
-
-        // Export macros are the recommended way, but might not be used
-        // in all cases (such as Qt headers). We handle it either way,
-        // macros or not. 
-        bool useLayerMacro = false;
-        if (installDir.startsWith("MW_LAYER_") ||
-            installDir.startsWith("APP_LAYER_") ||
-            installDir.startsWith("APP_LAYER_")) {
-            useLayerMacro = true;
-        } else {
-#ifdef Q_OS_WIN
-            // If we are running on Windows, and the export target starts
-            // with a drive letter, we need to remove it, the build tools
-            // cannot handle drives in export paths
-
-            if (installDir.length() > 2 && installDir[1] == ':') {
-                installDir.remove(0, 2);
-            }
-#endif
-            installDir.replace("\\", "/");
-            if (!installDir.endsWith("/")) {
-                installDir.append("/");
-            }
-        }
-
-        foreach(QString target, project->values(install + ".files")) {
-            // Handle glob targets (only in the current directory)
-            if (target.contains("*") || target.contains("?")) {
-                QDir globber = QDir::current();
-                globber.setNameFilters(QStringList(target));
-                foreach(QString globbedTarget, globber.entryList()) {
-                    if (useLayerMacro) {
-                        QFileInfo globbedInfo(globbedTarget);
-                        t << globbedTarget << " " << installDir <<
-                            "(" << globbedInfo.fileName() << ")" << endl;
-                    } else {
-                        t << globbedTarget << " " << installDir << 
-                            globbedTarget << endl;
-                    }
-                }
-            } else {
-                target = currentDir.relativeFilePath(target);
-                QFileInfo targetInfo(target);
-
-                // Not possible to export whole directories, extension makefile needed for this
-                // Note that this check requires the file to be exported to exist in the qmake phase!
-                if (targetInfo.isFile()) {
-                    if (useLayerMacro) {
-                        t << target << " " << installDir <<
-                            "(" << targetInfo.fileName() << ")" << endl;
-                    } else {
-                        t << target << " " << installDir <<
-                            targetInfo.fileName() << endl;
-                    }
-                }
-            }
-        }
-    }
-    t << endl;
-}
-
-void SymbianMakefileGenerator::writeRegRssFile(QStringList &userItems)
+void SymbianMakefileGenerator::writeRegRssFile(QMap<QString, QStringList> &userItems)
 {
     QString filename(fixedTarget);
     filename.append("_reg.rss");
@@ -1448,6 +1531,8 @@
         t << endl;
         t << "#include <" << fixedTarget << ".rsg>" << endl;
         t << "#include <appinfo.rh>" << endl;
+        foreach(QString item, userItems[RSS_TAG_HEADER])
+            t << item << endl;
         t << endl;
         t << "UID2 KUidAppRegistrationResourceFile" << endl;
         t << "UID3 " << uid3 << endl << endl;
@@ -1455,16 +1540,51 @@
         t << "\t{" << endl;
         t << "\tapp_file=\"" << fixedTarget << "\";" << endl;
         t << "\tlocalisable_resource_file=\"" RESOURCE_DIRECTORY_RESOURCE << fixedTarget << "\";" << endl;
+
+        writeRegRssList(t, userItems[RSS_TAG_SERVICE_LIST],
+                        QLatin1String(RSS_TAG_SERVICE_LIST),
+                        QLatin1String("SERVICE_INFO"));
+        writeRegRssList(t, userItems[RSS_TAG_FILE_OWNERSHIP_LIST],
+                        QLatin1String(RSS_TAG_FILE_OWNERSHIP_LIST),
+                        QLatin1String("FILE_OWNERSHIP_INFO"));
+        writeRegRssList(t, userItems[RSS_TAG_DATATYPE_LIST],
+                        QLatin1String(RSS_TAG_DATATYPE_LIST),
+                        QLatin1String("DATATYPE"));
         t << endl;
 
-        foreach(QString item, userItems)
-            t << "\t" << item << endl;
+        foreach(QString item, userItems[RSS_TAG_DEFAULT])
+            t << "\t" << item.replace("\n","\n\t") << endl;
         t << "\t}" << endl;
+
+        foreach(QString item, userItems[RSS_TAG_FOOTER])
+            t << item << endl;
     } else {
         PRINT_FILE_CREATE_ERROR(filename)
     }
 }
 
+void SymbianMakefileGenerator::writeRegRssList(QTextStream &t,
+                                               QStringList &userList,
+                                               const QString &listTag,
+                                               const QString &listItem)
+{
+    int itemCount = userList.count();
+    if (itemCount) {
+        t << "\t" << listTag << " ="<< endl;
+        t << "\t\t{" << endl;
+        foreach(QString item, userList) {
+            t << "\t\t" << listItem << endl;
+            t << "\t\t\t{" << endl;
+            t << "\t\t\t" << item.replace("\n","\n\t\t\t") << endl;
+            t << "\t\t\t}";
+            if (--itemCount)
+                t << ",";
+            t << endl;
+        }
+        t << "\t\t}; "<< endl;
+    }
+}
+
 void SymbianMakefileGenerator::writeRssFile(QString &numberOfIcons, QString &iconFile)
 {
     QString filename(fixedTarget);
@@ -1484,10 +1604,7 @@
         t << "// ============================================================================" << endl;
         t << endl;
         t << "#include <appinfo.rh>" << endl;
-        if (!project->values("SYMBIANTRANSLATIONS").isEmpty())
-            t << "#include <" << fixedTarget << ".loc>" << endl;
-        else
-            t << "#include \"" << fixedTarget << ".loc\"" << endl;
+        t << "#include <" << translationFileName << ".loc>" << endl;
         t << endl;
         t << "RESOURCE LOCALISABLE_APP_INFO r_localisable_app_info" << endl;
         t << "\t{" << endl;
@@ -1519,14 +1636,14 @@
 
 void SymbianMakefileGenerator::writeLocFile(QStringList &symbianLangCodes)
 {
-    QString filename(fixedTarget);
+    QString filename(translationFileName);
     if (project->values("SYMBIANTRANSLATIONS").isEmpty()) {
         filename.append(".loc");
     } else { 
         if (!project->first("SYMBIANLOCFILESDIR").isEmpty()) { 
             filename.insert(0,project->first("SYMBIANLOCFILESDIR"));         
         } else {	
-            filename.insert(0,"/epoc32/include/platform/app/loc/");    
+            filename.insert(0,"/epoc32/include/platform/mw/loc/");    
         }
         filename.append(".loc");
     }
@@ -1560,11 +1677,11 @@
         t << "#endif" << endl;
     } else {
             t << "#if LANGUAGE_01" << endl;    
-            t << "#include <" << "01/" << fixedTarget  << "_01.loc>" << endl;
+            t << "#include <" << "01/" << translationFileName  << "_01.loc>" << endl;
             foreach(QString lang, symbianLangCodes) {
                 if (lang.localeAwareCompare("01") != 0) {
                     t << "#elif LANGUAGE_" << lang << endl;
-                    t << "#include <" << lang << "/" << fixedTarget  << "_" << lang << ".loc>" << ">" << endl;
+                    t << "#include <" << lang << "/" << translationFileName  << "_" << lang << ".loc" << ">" << endl;
                 }
             }
             t << "#endif" << endl;
@@ -1576,13 +1693,14 @@
 
 void SymbianMakefileGenerator::writeSymbianLocFile(QStringList &symbianLangCodes)
 {	
-	QString filename(fixedTarget); 
+	QString filename(translationFileName); 
 	foreach(QString lang, symbianLangCodes) {
         
 		QString tsFilename(filename);  
 		QString language = qt2S60LangMapTable.key(lang, QString("en"));
 		tsFilename.append("_"+language+".ts");
-		tsFilename.insert(0,project->first("SYMBIANTRANSLATIONDIR")); 	
+	
+		tsFilename.insert(0,project->first("SYMBIANTRANSLATIONSRCDIR")); 	
 		
         QString locFilename(filename); 
         locFilename.append("_"+lang+".loc");
@@ -1590,7 +1708,7 @@
             locFilename.insert(0,lang+"/");
             locFilename.insert(0,project->first("SYMBIANLOCFILESDIR"));
         } else {	
-            locFilename.insert(0,"/epoc32/include/platform/app/loc/"+lang+"/");
+            locFilename.insert(0,"/epoc32/include/platform/mw/loc/"+lang+"/");
         }
                 
         QString shortCaption;
@@ -1633,17 +1751,22 @@
                         }
                     }         
                 }
-                if (shortCaption.isEmpty())
+                if (shortCaption.isEmpty()){
                     fprintf(stderr, "Warning: STRING_r_short_caption not generated from file '%s'.\n", qPrintable(tsFilename));
-                if (longCaption.isEmpty())
+                    fprintf(stderr, "       : short caption generated from target name '#%s'.\n", qPrintable(fixedTarget));
+                  }
+                if (longCaption.isEmpty()){
                     fprintf(stderr, "Warning: STRING_r_caption not generated from file '%s'.\n", qPrintable(tsFilename));
+                    fprintf(stderr, "       : caption generated from target name '#%s'.\n", qPrintable(fixedTarget));
+                  }
                 if (xml.hasError())
                     fprintf(stderr, "ERROR: \"%s\" when parsing ts file\n", qPrintable(xml.errorString()));
             } else {
                 fprintf(stderr, "Could not open ts file (%s)\n", qPrintable(tsFilename));
             }
         } else {
-            fprintf(stderr, "ts file does not exist: (%s)\n", qPrintable(tsFilename));
+            fprintf(stderr, "Warning: ts file does not exist: (%s)\n", qPrintable(tsFilename));
+            fprintf(stderr, "       : short and long caption generated from target name '#%s'.\n", qPrintable(fixedTarget));
         }
 
         // generate language specific caption loc file
@@ -1661,12 +1784,12 @@
             if (!shortCaption.isEmpty()) {
                 t << "#define STRING_r_short_caption \"" << shortCaption  << "\"" << endl;    
             } else {
-                t << "#define STRING_r_short_caption \"" << fixedTarget  << "\"" << endl;
+                t << "#define STRING_r_short_caption \"" "#"<< fixedTarget  << "\"" << endl;
             }    
             if (!longCaption.isEmpty()) {
                 t << "#define STRING_r_caption \"" << longCaption  << "\"" << endl;  
             } else {    
-                t << "#define STRING_r_caption \"" << fixedTarget  << "\"" << endl;
+                t << "#define STRING_r_caption \"" "#"<< fixedTarget  << "\"" << endl;
             }
             ft.close();
         } else {
@@ -1675,7 +1798,9 @@
     }
 }
 
-void SymbianMakefileGenerator::readRssRules(QString &numberOfIcons, QString &iconFile, QStringList &userRssRules)
+void SymbianMakefileGenerator::readRssRules(QString &numberOfIcons,
+                                            QString &iconFile, QMap<QString,
+                                            QStringList> &userRssRules)
 {
     for (QMap<QString, QStringList>::iterator it = project->variables().begin(); it != project->variables().end(); ++it) {
         if (it.key().startsWith(RSS_RULES_BASE)) {
@@ -1687,14 +1812,16 @@
             QStringList newValues;
             QStringList values = it.value();
             foreach(QString item, values) {
-                // If there is no stringlist defined for a rule, use rule name directly
+                // If there is no stringlist defined for a rule, use rule value directly
                 // This is convenience for defining single line statements
                 if (project->values(item).isEmpty()) {
                     newValues << item;
                 } else {
+                    QStringList itemList;
                     foreach(QString itemRow, project->values(item)) {
-                        newValues << itemRow;
+                        itemList << itemRow;
                     }
+                    newValues << itemList.join("\n");
                 }
             }
             // Verify thet there is exactly one value in RSS_TAG_NBROFICONS
@@ -1715,6 +1842,14 @@
                             RSS_RULES_BASE, RSS_TAG_ICONFILE);
                     continue;
                 }
+            } else if (newKey == RSS_TAG_HEADER
+                       || newKey == RSS_TAG_SERVICE_LIST
+                       || newKey == RSS_TAG_FILE_OWNERSHIP_LIST
+                       || newKey == RSS_TAG_DATATYPE_LIST
+                       || newKey == RSS_TAG_FOOTER
+                       || newKey == RSS_TAG_DEFAULT) {
+                userRssRules[newKey] = newValues;
+                continue;
             } else {
                 fprintf(stderr, "Warning: Unsupported key:'%s%s'\n",
                         RSS_RULES_BASE, newKey.toLatin1().constData());
@@ -1723,15 +1858,17 @@
         }
     }
 
+    QStringList newValues;
     foreach(QString item, project->values(RSS_RULES)) {
-        // If there is no stringlist defined for a rule, use rule name directly
-        // This is convenience for defining single line mmp statements
+        // If there is no stringlist defined for a rule, use rule value directly
+        // This is convenience for defining single line statements
         if (project->values(item).isEmpty()) {
-            userRssRules << item;
+            newValues << item;
         } else {
-            userRssRules << project->values(item);
+            newValues << project->values(item);
         }
     }
+    userRssRules[RSS_TAG_DEFAULT] << newValues;
 
     // Validate that either both RSS_TAG_NBROFICONS and RSS_TAG_ICONFILE keys exist
     // or neither of them exist
@@ -1747,7 +1884,7 @@
     if (!numberOfIcons.isEmpty()) {
         bool ok;
         numberOfIcons = numberOfIcons.simplified();
-        int tmp = numberOfIcons.toInt(&ok);
+        numberOfIcons.toInt(&ok);
         if (!ok) {
             numberOfIcons.clear();
             iconFile.clear();
@@ -2041,9 +2178,14 @@
 
 void SymbianMakefileGenerator::writeSisTargets(QTextStream &t)
 {
-    t << SIS_TARGET ": " RESTORE_BUILD_TARGET << endl;
-    QString siscommand = QString("\t$(if $(wildcard %1_template.%2),$(if $(wildcard %3)," \
-                                  "$(MAKE) -s -f $(MAKEFILE) %4,$(MAKE) -s -f $(MAKEFILE) %5)," \
+    t << "-include " MAKE_CACHE_NAME << endl;
+    t << endl;
+
+    t << SIS_TARGET ":" << endl;
+    QString siscommand = QString::fromLatin1("\t$(if $(wildcard %1_template.%2),$(if $(wildcard %3)," \
+                                  "$(MAKE) -s -f $(MAKEFILE) %4," \
+                                  "$(if $(QT_SIS_TARGET),$(MAKE) -s -f $(MAKEFILE) %4," \
+                                  "$(MAKE) -s -f $(MAKEFILE) %5))," \
                                   "$(MAKE) -s -f $(MAKEFILE) %6)")
                           .arg(fixedTarget)
                           .arg("pkg")
@@ -2056,24 +2198,69 @@
 
     t << OK_SIS_TARGET ":" << endl;
 
-    QString pkgcommand = QString("\tcreatepackage.bat $(QT_SIS_OPTIONS) %1_template.%2 $(QT_SIS_TARGET) " \
+    QString pkgcommand = QString::fromLatin1("\tcreatepackage.bat $(QT_SIS_OPTIONS) %1_template.%2 $(QT_SIS_TARGET) " \
                                  "$(QT_SIS_CERTIFICATE) $(QT_SIS_KEY) $(QT_SIS_PASSPHRASE)")
                           .arg(fixedTarget)
                           .arg("pkg");
     t << pkgcommand << endl;
     t << endl;
 
+    QString sisName = fixedTarget;
+    sisName += ".sis";
+
+    t << sisName << ":" << endl;
+    t << "\t$(MAKE) -s -f $(MAKEFILE) " SIS_TARGET << endl << endl;
+
+    t << ROM_STUB_SIS_TARGET ":" << endl;
+    QString stubsiscommand = QString::fromLatin1("\t$(if $(wildcard %1_template.%2),$(if $(wildcard %3)," \
+                                  "$(MAKE) -s -f $(MAKEFILE) %4," \
+                                  "$(if $(QT_SIS_TARGET),$(MAKE) -s -f $(MAKEFILE) %4," \
+                                  "$(MAKE) -s -f $(MAKEFILE) %5))," \
+                                  "$(MAKE) -s -f $(MAKEFILE) %6)")
+                          .arg(fixedTarget)
+                          .arg("pkg")
+                          .arg(MAKE_CACHE_NAME)
+                          .arg(OK_ROM_STUB_SIS_TARGET)
+                          .arg(FAIL_SIS_NOCACHE_TARGET)
+                          .arg(FAIL_SIS_NOPKG_TARGET);
+    t << stubsiscommand << endl;
+    t << endl;
+
+    t << OK_ROM_STUB_SIS_TARGET ":" << endl;
+
+    QString stubpkgcommand = QString::fromLatin1("\tcreatepackage.bat -s $(QT_SIS_OPTIONS) %1_template.%2 $(QT_SIS_TARGET) " \
+                                 "$(QT_SIS_CERTIFICATE) $(QT_SIS_KEY) $(QT_SIS_PASSPHRASE)")
+                          .arg(fixedTarget)
+                          .arg("pkg");
+    t << stubpkgcommand << endl;
+    t << endl;
+
+    t << INSTALLER_SIS_TARGET ": " << sisName << endl;
+    siscommand = QString::fromLatin1("\t$(if $(wildcard %1_installer.%2)," \
+                                  "$(MAKE) -s -f $(MAKEFILE) %3," \
+                                  "$(MAKE) -s -f $(MAKEFILE) %4)")
+                          .arg(fixedTarget)
+                          .arg("pkg")
+                          .arg(OK_INSTALLER_SIS_TARGET)
+                          .arg(FAIL_SIS_NOPKG_TARGET);
+    t << siscommand << endl;
+    t << endl;
+
+    t << OK_INSTALLER_SIS_TARGET ": " << endl;
+
+    pkgcommand = QString::fromLatin1("\tcreatepackage.bat $(QT_SIS_OPTIONS) %1_installer.%2 - " \
+                         "$(QT_SIS_CERTIFICATE) $(QT_SIS_KEY) $(QT_SIS_PASSPHRASE)")
+                  .arg(fixedTarget)
+                  .arg("pkg");
+    t << pkgcommand << endl;
+    t << endl;
+
     t << FAIL_SIS_NOPKG_TARGET ":" << endl;
-    t << "\t$(error PKG file does not exist, 'SIS' target is only supported for executables or projects with DEPLOYMENT statement)" << endl;
+    t << "\t$(error PKG file does not exist, '" SIS_TARGET "' and '" INSTALLER_SIS_TARGET "' target are only supported for executables or projects with DEPLOYMENT statement)" << endl;
     t << endl;
 
     t << FAIL_SIS_NOCACHE_TARGET ":" << endl;
-    t << "\t$(error Project has to be build before calling 'SIS' target)" << endl;
-    t << endl;
-
-
-    t << RESTORE_BUILD_TARGET ":" << endl;
-    t << "-include " MAKE_CACHE_NAME << endl;
+    t << "\t$(error Project has to be built or QT_SIS_TARGET environment variable has to be set before calling 'SIS' target)" << endl;
     t << endl;
 }
 
@@ -2131,3 +2318,17 @@
     t << "distclean: clean dodistclean" << endl;
     t << endl;
 }
+
+void SymbianMakefileGenerator::generateExecutionTargets(QTextStream& t, const QStringList& platforms)
+{
+    // create execution targets
+    if (targetType == TypeExe) {
+        if (platforms.contains("winscw")) {
+            t << "run:" << endl;
+            t << "\t-call " << epocRoot() << "epoc32/release/winscw/udeb/" << fixedTarget << ".exe " << "$(QT_RUN_OPTIONS)" << endl;
+        }
+        t << "runonphone: sis" << endl;
+        t << "\trunonphone $(QT_RUN_ON_PHONE_OPTIONS) --sis " << fixedTarget << ".sis " << fixedTarget << ".exe " << "$(QT_RUN_OPTIONS)" << endl;
+        t << endl;
+    }
+}