diff -r 2f34d5167611 -r fcece45ef507 qmake/generators/symbian/symmake.cpp --- a/qmake/generators/symbian/symmake.cpp Fri Apr 16 15:50:13 2010 +0300 +++ b/qmake/generators/symbian/symmake.cpp Mon May 03 13:17:34 2010 +0300 @@ -65,12 +65,18 @@ #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_EXPORTS "prj_exports" +#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" @@ -149,14 +155,14 @@ resultPath = QDir::fromNativeSeparators(epocRoot()) + resultPath.mid(1); QFileInfo fi(fileInfo(resultPath)); - + // 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 { - resultPath = fi.absoluteFilePath(); + resultPath = fi.absoluteFilePath(); } resultPath = QDir::cleanPath(resultPath); @@ -202,7 +208,7 @@ QString numberOfIcons; QString iconFile; - QStringList userRssRules; + QMap userRssRules; readRssRules(numberOfIcons, iconFile, userRssRules); // Get the application translations and convert to symbian OS lang code, i.e. decical number @@ -326,17 +332,36 @@ 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; + } } } } @@ -344,17 +369,17 @@ // 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) - QString languageCode = "; Language\n&EN\n\n"; - t << languageCode; - tw << languageCode; - } 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"; @@ -368,9 +393,10 @@ tw << installerSisHeader << endl; } - if (!containsStartWithItem('#', rawPkgPreRules)) { + if (headerRules.isEmpty()) t << sisHeader.arg(visualTarget).arg(uid3).arg(applicationVersion); - } + else + t << headerRules.join("\n") << endl; // Localized vendor name QString vendorName; @@ -460,14 +486,29 @@ // deploy any additional DEPLOYMENT files 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; @@ -779,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()) { @@ -961,6 +1000,7 @@ 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; @@ -1012,7 +1052,7 @@ 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; @@ -1240,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; @@ -1352,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(); @@ -1380,9 +1434,16 @@ bldinfDefine = bldinfDefine.toUpper(); removeSpecialCharacters(bldinfDefine); + if (!condition.isEmpty()) + t << "#if defined(" << condition << ")" << endl; + t << "#ifndef " << bldinfDefine << endl; t << "\t#include \"" << bldinfFilename << "\"" << endl; - t << "#endif // " << bldinfDefine << endl; + t << "#endif" << endl; + + if (!condition.isEmpty()) + t << "#endif" << endl; + } // Add supported project platforms @@ -1400,7 +1461,7 @@ // Add project mmps and old style extension makefiles QString mmpTag; - if (project->isActiveConfig("symbian_test")) + if (project->isActiveConfig(SYMBIAN_TEST_CONFIG)) mmpTag = QLatin1String(BLD_INF_TAG_TESTMMPFILES); else mmpTag = QLatin1String(BLD_INF_TAG_MMPFILES); @@ -1423,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 @@ -1442,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 &userItems) { QString filename(fixedTarget); filename.append("_reg.rss"); @@ -1535,6 +1531,8 @@ t << endl; t << "#include <" << fixedTarget << ".rsg>" << endl; t << "#include " << endl; + foreach(QString item, userItems[RSS_TAG_HEADER]) + t << item << endl; t << endl; t << "UID2 KUidAppRegistrationResourceFile" << endl; t << "UID3 " << uid3 << endl << endl; @@ -1542,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); @@ -1686,9 +1719,7 @@ if (tsFile.exists()) { if (tsFile.open(QIODevice::ReadOnly)) { QString shortCaptionId = QLatin1String("txt_short_caption_"); - shortCaptionId.append(filename); QString longCaptionId = QLatin1String("txt_long_caption_"); - longCaptionId.append(filename); QXmlStreamReader xml(&tsFile); while (!xml.atEnd()) { xml.readNext(); @@ -1697,7 +1728,7 @@ xml.readNext(); if (xml.isStartElement() && xml.name() == "message" && xml.attributes().value("numerus") == "no" && - xml.attributes().value("id") == shortCaptionId) { + xml.attributes().value("id").toString().left(shortCaptionId.length()) == shortCaptionId) { while (!(xml.isEndElement() && xml.name() == "message") && !xml.atEnd()) { xml.readNext(); if (xml.isStartElement() && xml.name() == "translation") { @@ -1707,7 +1738,7 @@ } if (xml.isStartElement() && xml.name() == "message" && xml.attributes().value("numerus") == "no" && - xml.attributes().value("id") == longCaptionId) { + xml.attributes().value("id").toString().left(longCaptionId.length()) == longCaptionId) { while (!(xml.isEndElement() && xml.name() == "message") && !xml.atEnd()) { xml.readNext(); if (xml.isStartElement() && xml.name() == "translation") { @@ -1719,8 +1750,7 @@ } } if (shortCaption.isEmpty()){ - fprintf(stderr, "Warning: STRING_r_short_caption not generated from file '%s'.\n", qPrintable(tsFilename)); - fprintf(stderr, " : short caption generated from target name '#%s'.\n", qPrintable(fixedTarget)); + 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)); @@ -1765,7 +1795,9 @@ } } -void SymbianMakefileGenerator::readRssRules(QString &numberOfIcons, QString &iconFile, QStringList &userRssRules) +void SymbianMakefileGenerator::readRssRules(QString &numberOfIcons, + QString &iconFile, QMap &userRssRules) { for (QMap::iterator it = project->variables().begin(); it != project->variables().end(); ++it) { if (it.key().startsWith(RSS_RULES_BASE)) { @@ -1777,14 +1809,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 @@ -1805,6 +1839,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()); @@ -1813,15 +1855,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 @@ -2281,7 +2325,7 @@ 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 << "_$(QT_SIS_TARGET).sis " << fixedTarget << ".exe " << "$(QT_RUN_OPTIONS)" << endl; + t << "\trunonphone $(QT_RUN_ON_PHONE_OPTIONS) --sis " << fixedTarget << ".sis " << fixedTarget << ".exe " << "$(QT_RUN_OPTIONS)" << endl; t << endl; } }