source: trunk/qmake/generators/symbian/symmake.cpp

Last change on this file was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

  • Property svn:eol-style set to native
File size: 41.1 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation (qt-info@nokia.com)
6**
7** This file is part of the qmake application of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at qt-info@nokia.com.
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "symmake.h"
43
44#include <qstring.h>
45#include <qhash.h>
46#include <qstringlist.h>
47#include <qdir.h>
48#include <qdatetime.h>
49#include <stdlib.h>
50#include <qdebug.h>
51
52// Included from tools/shared
53#include <symbian/epocroot_p.h>
54
55#define RESOURCE_DIRECTORY_MMP "/resource/apps"
56#define REGISTRATION_RESOURCE_DIRECTORY_HW "/private/10003a3f/import/apps"
57#define PLUGIN_COMMON_DEF_FILE_FOR_MMP "./plugin_common.def"
58#define BLD_INF_FILENAME_LEN (sizeof(BLD_INF_FILENAME) - 1)
59
60#define BLD_INF_RULES_BASE "BLD_INF_RULES."
61#define BLD_INF_TAG_PLATFORMS "prj_platforms"
62#define BLD_INF_TAG_MMPFILES "prj_mmpfiles"
63#define BLD_INF_TAG_TESTMMPFILES "prj_testmmpfiles"
64#define BLD_INF_TAG_EXTENSIONS "prj_extensions"
65#define BLD_INF_TAG_TESTEXTENSIONS "prj_testextensions"
66
67#define MMP_TARGET "TARGET"
68#define MMP_TARGETTYPE "TARGETTYPE"
69#define MMP_SECUREID "SECUREID"
70#define MMP_OPTION "OPTION"
71#define MMP_LINKEROPTION "LINKEROPTION"
72#define MMP_CAPABILITY "CAPABILITY"
73#define MMP_EPOCALLOWDLLDATA "EPOCALLOWDLLDATA"
74#define MMP_EPOCHEAPSIZE "EPOCHEAPSIZE"
75#define MMP_EPOCSTACKSIZE "EPOCSTACKSIZE"
76#define MMP_UID "UID"
77#define MMP_VENDORID "VENDORID"
78#define MMP_VERSION "VERSION"
79#define MMP_START_RESOURCE "START RESOURCE"
80#define MMP_END_RESOURCE "END"
81
82#define VAR_CXXFLAGS "QMAKE_CXXFLAGS"
83#define VAR_CFLAGS "QMAKE_CFLAGS"
84#define VAR_LFLAGS "QMAKE_LFLAGS"
85
86#define DEFINE_REPLACE_REGEXP "[^A-Z0-9_]"
87
88QString SymbianMakefileGenerator::fixPathForMmp(const QString& origPath, const QDir& parentDir)
89{
90 static QString epocRootStr;
91 if (epocRootStr.isEmpty()) {
92 epocRootStr = qt_epocRoot();
93 QFileInfo efi(epocRootStr);
94 if (!efi.exists() || epocRootStr.isEmpty()) {
95 fprintf(stderr, "Unable to resolve epocRoot '%s' to real dir on current drive, defaulting to '/' for mmp paths\n", qPrintable(qt_epocRoot()));
96 epocRootStr = "/";
97 } else {
98 epocRootStr = efi.absoluteFilePath();
99 }
100 if (!epocRootStr.endsWith("/"))
101 epocRootStr += "/";
102
103 epocRootStr += "epoc32/";
104 }
105
106 QString resultPath = origPath;
107
108 // Make it relative, unless it starts with "%epocroot%/epoc32/"
109 if (resultPath.startsWith(epocRootStr, Qt::CaseInsensitive)) {
110 resultPath.replace(epocRootStr, "/epoc32/", Qt::CaseInsensitive);
111 } else {
112 resultPath = parentDir.relativeFilePath(resultPath);
113 }
114 resultPath = QDir::cleanPath(resultPath);
115
116 if (resultPath.isEmpty())
117 resultPath = ".";
118
119 return resultPath;
120}
121
122QString SymbianMakefileGenerator::absolutizePath(const QString& origPath)
123{
124 // Prepend epocroot to any paths beginning with "/epoc32/"
125 QString resultPath = QDir::fromNativeSeparators(origPath);
126 if (resultPath.startsWith("/epoc32/", Qt::CaseInsensitive))
127 resultPath = QDir::fromNativeSeparators(qt_epocRoot()) + resultPath.mid(1);
128
129 QFileInfo fi(fileInfo(resultPath));
130
131 // Since origPath can be something given in HEADERS, we need to check if we are dealing
132 // with a file or a directory. In case the origPath doesn't yet exist, isFile() returns
133 // false and we default to assuming it is a dir.
134 if (fi.isFile()) {
135 resultPath = fi.absolutePath();
136 } else {
137 resultPath = fi.absoluteFilePath();
138 }
139
140 resultPath = QDir::cleanPath(resultPath);
141
142 return resultPath;
143}
144
145SymbianMakefileGenerator::SymbianMakefileGenerator() : MakefileGenerator(), SymbianCommonGenerator(this) { }
146SymbianMakefileGenerator::~SymbianMakefileGenerator() { }
147
148void SymbianMakefileGenerator::writeHeader(QTextStream &t)
149{
150 t << "// ============================================================================" << endl;
151 t << "// * Makefile for building: " << escapeFilePath(var("TARGET")) << endl;
152 t << "// * Generated by qmake (" << qmake_version() << ") (Qt " QT_VERSION_STR ") on: ";
153 t << QDateTime::currentDateTime().toString(Qt::ISODate) << endl;
154 t << "// * This file is generated by qmake and should not be modified by the" << endl;
155 t << "// * user." << endl;
156 t << "// * Project: " << fileFixify(project->projectFile()) << endl;
157 t << "// * Template: " << var("TEMPLATE") << endl;
158 t << "// ============================================================================" << endl;
159 t << endl;
160
161 // Defining define for bld.inf
162
163 QString shortProFilename = project->projectFile();
164 shortProFilename.replace(0, shortProFilename.lastIndexOf("/") + 1, QString(""));
165 shortProFilename.replace(Option::pro_ext, QString(""));
166
167 QString bldinfDefine = shortProFilename;
168 bldinfDefine.append("_");
169 bldinfDefine.append(generate_uid(project->projectFile()));
170 bldinfDefine = bldinfDefine.toUpper();
171
172 // replace anything not alphanumeric with underscore
173 QRegExp replacementMask(DEFINE_REPLACE_REGEXP);
174 bldinfDefine.replace(replacementMask, QLatin1String("_"));
175
176 bldinfDefine.prepend("BLD_INF_");
177
178 t << "#define " << bldinfDefine << endl << endl;
179}
180
181bool SymbianMakefileGenerator::writeMakefile(QTextStream &t)
182{
183 if(!project->values("QMAKE_FAILED_REQUIREMENTS").isEmpty()) {
184 fprintf(stderr, "Project files not generated because all requirements are not met:\n\t%s\n",
185 qPrintable(var("QMAKE_FAILED_REQUIREMENTS")));
186 return false;
187 }
188
189 writeHeader(t);
190
191 QString numberOfIcons;
192 QString iconFile;
193 QMap<QString, QStringList> userRssRules;
194 readRssRules(numberOfIcons, iconFile, userRssRules);
195
196 SymbianLocalizationList symbianLocalizationList;
197 parseTsFiles(&symbianLocalizationList);
198
199 // Generate pkg files if there are any actual files to deploy
200 bool generatePkg = false;
201
202 if (targetType == TypeExe) {
203 generatePkg = true;
204 } else {
205 foreach(QString item, project->values("DEPLOYMENT")) {
206 if (!project->values(item + ".sources").isEmpty()) {
207 generatePkg = true;
208 break;
209 }
210 }
211 }
212
213 if (generatePkg) {
214 generatePkgFile(iconFile, true, symbianLocalizationList);
215 }
216
217 writeBldInfContent(t, generatePkg, iconFile);
218
219 // Generate empty wrapper makefile here, because wrapper makefile must exist before writeMkFile,
220 // but all required data is not yet available.
221 bool isPrimaryMakefile = true;
222 QString wrapperFileName = Option::output_dir + QLatin1Char('/') + QLatin1String("Makefile");
223 QString outputFileName = fileInfo(Option::output.fileName()).fileName();
224 if (outputFileName != BLD_INF_FILENAME) {
225 wrapperFileName.append(".").append(outputFileName.startsWith(BLD_INF_FILENAME)
226 ? outputFileName.mid(sizeof(BLD_INF_FILENAME))
227 : outputFileName);
228 isPrimaryMakefile = false;
229 }
230
231 QFile wrapperMakefile(wrapperFileName);
232 if (wrapperMakefile.open(QIODevice::WriteOnly)) {
233 generatedFiles << wrapperFileName;
234 } else {
235 PRINT_FILE_CREATE_ERROR(wrapperFileName);
236 return false;
237 }
238
239 if (targetType == TypeSubdirs) {
240 // If we have something to deploy, generate extension makefile for just that, since
241 // normal extension makefile is not getting generated and we need emulator deployment to be done.
242 if (generatePkg)
243 writeMkFile(wrapperFileName, true);
244 writeWrapperMakefile(wrapperMakefile, isPrimaryMakefile);
245 return true;
246 }
247
248 writeMkFile(wrapperFileName, false);
249
250 QString absoluteMmpFileName = Option::output_dir + QLatin1Char('/') + mmpFileName;
251 writeMmpFile(absoluteMmpFileName, symbianLocalizationList);
252
253 if (targetType == TypeExe) {
254 if (!project->isActiveConfig("no_icon")) {
255 writeRegRssFile(userRssRules);
256 writeRssFile(numberOfIcons, iconFile);
257 writeLocFile(symbianLocalizationList);
258 }
259 }
260
261 writeCustomDefFile();
262 writeWrapperMakefile(wrapperMakefile, isPrimaryMakefile);
263
264 return true;
265}
266
267void SymbianMakefileGenerator::init()
268{
269 MakefileGenerator::init();
270 SymbianCommonGenerator::init();
271
272 if (0 != project->values("QMAKE_PLATFORM").size())
273 platform = varGlue("QMAKE_PLATFORM", "", " ", "");
274
275 if (0 == project->values("QMAKESPEC").size())
276 project->values("QMAKESPEC").append(qgetenv("QMAKESPEC"));
277
278 project->values("QMAKE_LIBS") += escapeFilePaths(project->values("LIBS"));
279 project->values("QMAKE_LIBS_PRIVATE") += escapeFilePaths(project->values("LIBS_PRIVATE"));
280
281 // Disallow renaming of bld.inf.
282 project->values("MAKEFILE").clear();
283 project->values("MAKEFILE") += BLD_INF_FILENAME;
284
285 // .mmp
286 mmpFileName = fixedTarget;
287 if (targetType == TypeExe)
288 mmpFileName.append("_exe");
289 else if (targetType == TypeDll || targetType == TypePlugin)
290 mmpFileName.append("_dll");
291 else if (targetType == TypeLib)
292 mmpFileName.append("_lib");
293 mmpFileName.append(Option::mmp_ext);
294
295 initMmpVariables();
296
297 uid2 = project->first("TARGET.UID2");
298
299 uid2 = uid2.trimmed();
300}
301
302QString SymbianMakefileGenerator::getTargetExtension()
303{
304 QString ret;
305 if (targetType == TypeExe) {
306 ret.append("exe");
307 } else if (targetType == TypeLib) {
308 ret.append("lib");
309 } else if (targetType == TypeDll || targetType == TypePlugin) {
310 ret.append("dll");
311 } else if (targetType == TypeSubdirs) {
312 // Not actually usable, so return empty
313 } else {
314 // If nothing else set, default to exe
315 ret.append("exe");
316 }
317
318 return ret;
319}
320
321QString SymbianMakefileGenerator::generateUID3()
322{
323 QString target = project->first("TARGET");
324 QString currPath = qmake_getpwd();
325 target.prepend("/").prepend(currPath);
326 return generate_test_uid(target);
327}
328
329void SymbianMakefileGenerator::initMmpVariables()
330{
331 QStringList sysincspaths;
332 QStringList srcincpaths;
333 QStringList srcpaths;
334
335 srcpaths << project->values("SOURCES") << project->values("GENERATED_SOURCES");
336 srcpaths << project->values("UNUSED_SOURCES") << project->values("UI_SOURCES_DIR");
337 srcpaths << project->values("UI_DIR");
338
339 QDir current = QDir::current();
340 QString absolutizedCurrent = absolutizePath(".");
341
342 for (int j = 0; j < srcpaths.size(); ++j) {
343 QFileInfo fi(fileInfo(srcpaths.at(j)));
344 // Sometimes sources have other than *.c* files (e.g. *.moc); prune them.
345 if (fi.suffix().startsWith("c")) {
346 if (fi.filePath().length() > fi.fileName().length()) {
347 appendIfnotExist(srcincpaths, fi.path());
348 sources[absolutizePath(fi.path())] += fi.fileName();
349 } else {
350 sources[absolutizedCurrent] += fi.fileName();
351 appendIfnotExist(srcincpaths, absolutizedCurrent);
352 }
353 }
354 }
355
356 QStringList incpaths;
357 incpaths << project->values("INCLUDEPATH");
358 incpaths << QLibraryInfo::location(QLibraryInfo::HeadersPath);
359 incpaths << project->values("HEADERS");
360 incpaths << srcincpaths;
361 incpaths << project->values("UI_HEADERS_DIR");
362 incpaths << project->values("UI_DIR");
363
364 for (int j = 0; j < incpaths.size(); ++j) {
365 QString includepath = absolutizePath(incpaths.at(j));
366 appendIfnotExist(sysincspaths, includepath);
367 appendAbldTempDirs(sysincspaths, includepath);
368 }
369
370 // Remove duplicate include path entries
371 QStringList temporary;
372 for (int i = 0; i < sysincspaths.size(); ++i) {
373 QString origPath = sysincspaths.at(i);
374 QFileInfo origPathInfo(fileInfo(origPath));
375 bool bFound = false;
376
377 for (int j = 0; j < temporary.size(); ++j) {
378 QString tmpPath = temporary.at(j);
379 QFileInfo tmpPathInfo(fileInfo(tmpPath));
380
381 if (origPathInfo.absoluteFilePath() == tmpPathInfo.absoluteFilePath()) {
382 bFound = true;
383 if (!tmpPathInfo.isRelative() && origPathInfo.isRelative()) {
384 // We keep the relative notation
385 temporary.removeOne(tmpPath);
386 temporary << origPath;
387 }
388 }
389 }
390
391 if (!bFound)
392 temporary << origPath;
393
394 }
395
396 sysincspaths.clear();
397 sysincspaths << temporary;
398
399 systeminclude.insert("SYSTEMINCLUDE", sysincspaths);
400
401 // Check MMP_RULES for singleton keywords that are overridden
402 QStringList overridableMmpKeywords;
403 QStringList restrictableMmpKeywords;
404 QStringList restrictedMmpKeywords;
405 bool inResourceBlock = false;
406
407 overridableMmpKeywords << QLatin1String(MMP_TARGETTYPE) << QLatin1String(MMP_EPOCHEAPSIZE);
408 restrictableMmpKeywords << QLatin1String(MMP_TARGET) << QLatin1String(MMP_SECUREID)
409 << QLatin1String(MMP_OPTION) << QLatin1String(MMP_LINKEROPTION)
410 << QLatin1String(MMP_CAPABILITY) << QLatin1String(MMP_EPOCALLOWDLLDATA)
411 << QLatin1String(MMP_EPOCSTACKSIZE) << QLatin1String(MMP_UID)
412 << QLatin1String(MMP_VENDORID) << QLatin1String(MMP_VERSION);
413
414 foreach (QString item, project->values("MMP_RULES")) {
415 if (project->values(item).isEmpty()) {
416 handleMmpRulesOverrides(item, inResourceBlock, restrictedMmpKeywords,
417 restrictableMmpKeywords, overridableMmpKeywords);
418 } else {
419 foreach (QString itemRow, project->values(item)) {
420 handleMmpRulesOverrides(itemRow, inResourceBlock, restrictedMmpKeywords,
421 restrictableMmpKeywords, overridableMmpKeywords);
422 }
423 }
424 }
425
426 if (restrictedMmpKeywords.size()) {
427 fprintf(stderr, "Warning: Restricted statements detected in MMP_RULES:\n"
428 " (%s)\n"
429 " Use corresponding qmake variable(s) instead.\n",
430 qPrintable(restrictedMmpKeywords.join(", ")));
431 }
432}
433
434void SymbianMakefileGenerator::handleMmpRulesOverrides(QString &checkString,
435 bool &inResourceBlock,
436 QStringList &restrictedMmpKeywords,
437 const QStringList &restrictableMmpKeywords,
438 const QStringList &overridableMmpKeywords)
439{
440 QString simplifiedString = checkString.simplified();
441
442 if (!inResourceBlock && simplifiedString.startsWith(MMP_START_RESOURCE, Qt::CaseInsensitive))
443 inResourceBlock = true;
444 else if (inResourceBlock && simplifiedString.startsWith(MMP_END_RESOURCE, Qt::CaseInsensitive))
445 inResourceBlock = false;
446
447 // Allow restricted and overridable items in RESOURCE blocks as those do not actually
448 // override anything.
449 if (!inResourceBlock) {
450 appendKeywordIfMatchFound(overriddenMmpKeywords, overridableMmpKeywords, simplifiedString);
451 appendKeywordIfMatchFound(restrictedMmpKeywords, restrictableMmpKeywords, simplifiedString);
452 }
453}
454
455void SymbianMakefileGenerator::appendKeywordIfMatchFound(QStringList &list,
456 const QStringList &keywordList,
457 QString &checkString)
458{
459 // Check if checkString starts with any supplied keyword and
460 // add the found keyword to list if it does.
461 foreach (QString item, keywordList) {
462 if (checkString.startsWith(QString(item).append(" "), Qt::CaseInsensitive)
463 || checkString.compare(item, Qt::CaseInsensitive) == 0) {
464 appendIfnotExist(list, item);
465 }
466 }
467}
468
469
470bool SymbianMakefileGenerator::removeDuplicatedStrings(QStringList &stringList)
471{
472 QStringList tmpStringList;
473
474 for (int i = 0; i < stringList.size(); ++i) {
475 QString string = stringList.at(i);
476 if (tmpStringList.contains(string))
477 continue;
478 else
479 tmpStringList.append(string);
480 }
481
482 stringList.clear();
483 stringList = tmpStringList;
484 return true;
485}
486
487void SymbianMakefileGenerator::writeMmpFileHeader(QTextStream &t)
488{
489 t << "// ==============================================================================" << endl;
490 t << "// Generated by qmake (" << qmake_version() << ") (Qt " QT_VERSION_STR ") on: ";
491 t << QDateTime::currentDateTime().toString(Qt::ISODate) << endl;
492 t << "// This file is generated by qmake and should not be modified by the" << endl;
493 t << "// user." << endl;
494 t << "// Name : " << mmpFileName << endl;
495 t << "// ==============================================================================" << endl << endl;
496}
497
498void SymbianMakefileGenerator::writeMmpFile(QString &filename, const SymbianLocalizationList &symbianLocalizationList)
499{
500 QFile ft(filename);
501 if (ft.open(QIODevice::WriteOnly)) {
502 generatedFiles << ft.fileName();
503
504 QTextStream t(&ft);
505
506 writeMmpFileHeader(t);
507
508 writeMmpFileTargetPart(t);
509
510 writeMmpFileResourcePart(t, symbianLocalizationList);
511
512 writeMmpFileMacrosPart(t);
513
514 writeMmpFileIncludePart(t);
515
516 QDir current = QDir::current();
517
518 for (QMap<QString, QStringList>::iterator it = sources.begin(); it != sources.end(); ++it) {
519 QStringList values = it.value();
520 QString currentSourcePath = it.key();
521
522 if (values.size())
523 t << "SOURCEPATH \t" << fixPathForMmp(currentSourcePath, current) << endl;
524
525 for (int i = 0; i < values.size(); ++i) {
526 QString sourceFileName = values.at(i);
527 t << "SOURCE\t\t" << sourceFileName << endl;
528 }
529 t << endl;
530 }
531 t << endl;
532
533 if (!project->isActiveConfig("static") && !project->isActiveConfig("staticlib")) {
534 writeMmpFileLibraryPart(t);
535 }
536
537 writeMmpFileCapabilityPart(t);
538
539 writeMmpFileCompilerOptionPart(t);
540
541 writeMmpFileBinaryVersionPart(t);
542
543 writeMmpFileRulesPart(t);
544 } else {
545 PRINT_FILE_CREATE_ERROR(filename)
546 }
547}
548
549void SymbianMakefileGenerator::writeMmpFileMacrosPart(QTextStream& t)
550{
551 t << endl;
552
553 QStringList &defines = project->values("DEFINES");
554 if (defines.size())
555 t << "// Qt Macros" << endl;
556 for (int i = 0; i < defines.size(); ++i) {
557 QString def = defines.at(i);
558 addMacro(t, def);
559 }
560
561 // These are required in order that all methods will be correctly exported e.g from qtestlib
562 QStringList &exp_defines = project->values("PRL_EXPORT_DEFINES");
563 if (exp_defines.size())
564 t << endl << "// Qt Export Defines" << endl;
565 for (int i = 0; i < exp_defines.size(); ++i) {
566 QString def = exp_defines.at(i);
567 addMacro(t, def);
568 }
569
570 t << endl;
571}
572
573void SymbianMakefileGenerator::addMacro(QTextStream& t, const QString& value)
574{
575 t << "MACRO\t\t" << value << endl;
576}
577
578
579void SymbianMakefileGenerator::writeMmpFileTargetPart(QTextStream& t)
580{
581 bool skipTargetType = overriddenMmpKeywords.contains(MMP_TARGETTYPE);
582 bool skipEpocHeapSize = overriddenMmpKeywords.contains(MMP_EPOCHEAPSIZE);
583
584 if (targetType == TypeExe) {
585 t << MMP_TARGET "\t\t" << fixedTarget << ".exe" << endl;
586 if (!skipTargetType) {
587 if (project->isActiveConfig("stdbinary"))
588 t << MMP_TARGETTYPE "\t\tSTDEXE" << endl;
589 else
590 t << MMP_TARGETTYPE "\t\tEXE" << endl;
591 }
592 } else if (targetType == TypeDll || targetType == TypePlugin) {
593 t << MMP_TARGET "\t\t" << fixedTarget << ".dll" << endl;
594 if (!skipTargetType) {
595 if (project->isActiveConfig("stdbinary"))
596 t << MMP_TARGETTYPE "\t\tSTDDLL" << endl;
597 else
598 t << MMP_TARGETTYPE "\t\tDLL" << endl;
599 }
600 } else if (targetType == TypeLib) {
601 t << MMP_TARGET "\t\t" << fixedTarget << ".lib" << endl;
602 if (!skipTargetType) {
603 if (project->isActiveConfig("stdbinary"))
604 t << MMP_TARGETTYPE "\t\tSTDLIB" << endl;
605 else
606 t << MMP_TARGETTYPE "\t\tLIB" << endl;
607 }
608 } else {
609 fprintf(stderr, "Error: Unexpected targettype (%d) in SymbianMakefileGenerator::writeMmpFileTargetPart\n", targetType);
610 }
611
612 t << endl;
613
614 t << MMP_UID "\t\t" << uid2 << " " << uid3 << endl;
615
616 if (0 != project->values("TARGET.SID").size()) {
617 t << MMP_SECUREID "\t\t" << project->values("TARGET.SID").join(" ") << endl;
618 } else {
619 if (0 == uid3.size())
620 t << MMP_SECUREID "\t\t0" << endl;
621 else
622 t << MMP_SECUREID "\t\t" << uid3 << endl;
623 }
624
625 // default value used from mkspecs is 0
626 if (0 != project->values("TARGET.VID").size()) {
627 t << MMP_VENDORID "\t\t" << project->values("TARGET.VID").join(" ") << endl;
628 }
629
630 t << endl;
631
632 if (0 != project->first("TARGET.EPOCSTACKSIZE").size())
633 t << MMP_EPOCSTACKSIZE "\t\t" << project->first("TARGET.EPOCSTACKSIZE") << endl;
634 if (!skipEpocHeapSize && 0 != project->values("TARGET.EPOCHEAPSIZE").size())
635 t << MMP_EPOCHEAPSIZE "\t\t" << project->values("TARGET.EPOCHEAPSIZE").join(" ") << endl;
636 if (0 != project->values("TARGET.EPOCALLOWDLLDATA").size())
637 t << MMP_EPOCALLOWDLLDATA << endl;
638
639 if (targetType == TypePlugin && !project->isActiveConfig("stdbinary")) {
640 // Use custom def file for Qt plugins
641 t << "DEFFILE " PLUGIN_COMMON_DEF_FILE_FOR_MMP << endl;
642 }
643
644 t << endl;
645}
646
647
648/*
649 Application registration resource files should be installed to the
650 \private\10003a3f\import\apps directory.
651*/
652void SymbianMakefileGenerator::writeMmpFileResourcePart(QTextStream& t, const SymbianLocalizationList &symbianLocalizationList)
653{
654 if ((targetType == TypeExe) &&
655 !project->isActiveConfig("no_icon")) {
656
657 QString locTarget = fixedTarget;
658 locTarget.append(".rss");
659
660 t << "SOURCEPATH\t\t\t. " << endl;
661 t << "LANG SC "; // no endl
662 SymbianLocalizationListIterator iter(symbianLocalizationList);
663 while (iter.hasNext()) {
664 const SymbianLocalization &loc = iter.next();
665 t << loc.symbianLanguageCode << " "; // no endl
666 }
667 t << endl;
668 t << MMP_START_RESOURCE "\t\t" << locTarget << endl;
669 t << "HEADER" << endl;
670 t << "TARGETPATH\t\t\t" RESOURCE_DIRECTORY_MMP << endl;
671 t << MMP_END_RESOURCE << endl << endl;
672
673 QString regTarget = fixedTarget;
674 regTarget.append("_reg.rss");
675
676 t << "SOURCEPATH\t\t\t." << endl;
677 t << MMP_START_RESOURCE "\t\t" << regTarget << endl;
678 if (isForSymbianSbsv2())
679 t << "DEPENDS " << fixedTarget << ".rsg" << endl;
680 t << "TARGETPATH\t\t" REGISTRATION_RESOURCE_DIRECTORY_HW << endl;
681 t << MMP_END_RESOURCE << endl << endl;
682 }
683}
684
685void SymbianMakefileGenerator::writeMmpFileSystemIncludePart(QTextStream& t)
686{
687 QDir current = QDir::current();
688
689 for (QMap<QString, QStringList>::iterator it = systeminclude.begin(); it != systeminclude.end(); ++it) {
690 QStringList values = it.value();
691 for (int i = 0; i < values.size(); ++i) {
692 QString handledPath = values.at(i);
693 t << "SYSTEMINCLUDE\t\t" << fixPathForMmp(handledPath, current) << endl;
694 }
695 }
696
697 t << endl;
698}
699
700void SymbianMakefileGenerator::writeMmpFileIncludePart(QTextStream& t)
701{
702 writeMmpFileSystemIncludePart(t);
703}
704
705void SymbianMakefileGenerator::writeMmpFileLibraryPart(QTextStream& t)
706{
707 QStringList &libs = project->values("LIBS");
708 libs << project->values("QMAKE_LIBS") << project->values("QMAKE_LIBS_PRIVATE");
709
710 removeDuplicatedStrings(libs);
711
712 for (int i = 0; i < libs.size(); ++i) {
713 QString lib = libs.at(i);
714 // The -L flag is uninteresting, since all symbian libraries exist in the same directory.
715 if (lib.startsWith("-l")) {
716 lib.remove(0, 2);
717 QString mmpStatement;
718 if (lib.endsWith(".dll")) {
719 lib.chop(4);
720 mmpStatement = "LIBRARY\t\t";
721 } else if (lib.endsWith(".lib")) {
722 lib.chop(4);
723 mmpStatement = "STATICLIBRARY\t";
724 } else {
725 // Hacky way to find out what kind of library it is. Check the
726 // ARMV5 build directory for library type. We default to shared
727 // library, since that is more common.
728 QString udebStaticLibLocation(qt_epocRoot());
729 QString urelStaticLibLocation(udebStaticLibLocation);
730 udebStaticLibLocation += QString("epoc32/release/armv5/udeb/%1.lib").arg(lib);
731 urelStaticLibLocation += QString("epoc32/release/armv5/urel/%1.lib").arg(lib);
732 if (QFile::exists(udebStaticLibLocation) || QFile::exists(urelStaticLibLocation)) {
733 mmpStatement = "STATICLIBRARY\t";
734 } else {
735 mmpStatement = "LIBRARY\t\t";
736 }
737 }
738 t << mmpStatement << lib << ".lib" << endl;
739 }
740 }
741
742 t << endl;
743}
744
745void SymbianMakefileGenerator::writeMmpFileCapabilityPart(QTextStream& t)
746{
747 if (0 != project->first("TARGET.CAPABILITY").size()) {
748 QStringList &capabilities = project->values("TARGET.CAPABILITY");
749 t << MMP_CAPABILITY "\t\t";
750
751 for (int i = 0; i < capabilities.size(); ++i) {
752 QString cap = capabilities.at(i);
753 t << cap << " ";
754 }
755 } else {
756 t << MMP_CAPABILITY "\t\tNone";
757 }
758 t << endl << endl;
759}
760
761void SymbianMakefileGenerator::writeMmpFileConditionalOptions(QTextStream& t,
762 const QString &optionType,
763 const QString &optionTag,
764 const QString &variableBase)
765{
766 foreach(QString compilerVersion, project->values("VERSION_FLAGS." + optionTag)) {
767 QStringList currentValues = project->values(variableBase + "." + compilerVersion);
768 if (currentValues.size()) {
769 t << "#if defined(" << compilerVersion << ")" << endl;
770 t << optionType << " " << optionTag << " " << currentValues.join(" ") << endl;
771 t << "#endif" << endl;
772 }
773 }
774}
775
776void SymbianMakefileGenerator::writeMmpFileSimpleOption(QTextStream& t,
777 const QString &optionType,
778 const QString &optionTag,
779 const QString &options)
780{
781 QString trimmedOptions = options.trimmed();
782 if (!trimmedOptions.isEmpty())
783 t << optionType << " " << optionTag << " " << trimmedOptions << endl;
784}
785
786void SymbianMakefileGenerator::appendMmpFileOptions(QString &options, const QStringList &list)
787{
788 if (list.size()) {
789 options.append(list.join(" "));
790 options.append(" ");
791 }
792}
793
794void SymbianMakefileGenerator::writeMmpFileCompilerOptionPart(QTextStream& t)
795{
796 QStringList keywords = project->values("MMP_OPTION_KEYWORDS");
797 QStringList commonCxxFlags = project->values(VAR_CXXFLAGS);
798 QStringList commonCFlags = project->values(VAR_CFLAGS);
799 QStringList commonLFlags = project->values(VAR_LFLAGS);
800
801 foreach(QString item, keywords) {
802 QString compilerOption;
803 QString linkerOption;
804
805 appendMmpFileOptions(compilerOption, project->values(VAR_CXXFLAGS "." + item));
806 appendMmpFileOptions(compilerOption, project->values(VAR_CFLAGS "." + item));
807 appendMmpFileOptions(compilerOption, commonCxxFlags);
808 appendMmpFileOptions(compilerOption, commonCFlags);
809
810 appendMmpFileOptions(linkerOption, project->values(VAR_LFLAGS "." + item));
811 appendMmpFileOptions(linkerOption, commonLFlags);
812
813 writeMmpFileSimpleOption(t, MMP_OPTION, item, compilerOption);
814 writeMmpFileSimpleOption(t, MMP_LINKEROPTION, item, linkerOption);
815
816 writeMmpFileConditionalOptions(t, MMP_OPTION, item, VAR_CXXFLAGS);
817 writeMmpFileConditionalOptions(t, MMP_LINKEROPTION, item, VAR_LFLAGS);
818 }
819
820 t << endl;
821}
822
823void SymbianMakefileGenerator::writeMmpFileBinaryVersionPart(QTextStream& t)
824{
825 QString applicationVersion = project->first("VERSION");
826 QStringList verNumList = applicationVersion.split('.');
827 uint major = 0;
828 uint minor = 0;
829 uint patch = 0;
830 bool success = false;
831
832 if (verNumList.size() > 0) {
833 major = verNumList[0].toUInt(&success);
834 if (success && verNumList.size() > 1) {
835 minor = verNumList[1].toUInt(&success);
836 if (success && verNumList.size() > 2) {
837 patch = verNumList[2].toUInt(&success);
838 }
839 }
840 }
841
842 QString mmpVersion;
843 if (success && major <= 0xFFFF && minor <= 0xFF && patch <= 0xFF) {
844 // Symbian binary version only has major and minor components, so compress
845 // Qt's minor and patch values into the minor component. Since Symbian's minor
846 // component is a 16 bit value, only allow 8 bits for each to avoid overflow.
847 mmpVersion.append(QString::number(major))
848 .append('.')
849 .append(QString::number((minor << 8) + patch));
850 } else {
851 if (!applicationVersion.isEmpty())
852 fprintf(stderr, "Invalid VERSION string: %s\n", qPrintable(applicationVersion));
853 mmpVersion = "10.0"; // Default binary version for symbian is 10.0
854 }
855
856 t << MMP_VERSION " " << mmpVersion << endl;
857}
858
859void SymbianMakefileGenerator::writeMmpFileRulesPart(QTextStream& t)
860{
861 foreach(QString item, project->values("MMP_RULES")) {
862 t << endl;
863 // If there is no stringlist defined for a rule, use rule name directly
864 // This is convenience for defining single line mmp statements
865 if (project->values(item).isEmpty()) {
866 t << item << endl;
867 } else {
868 foreach(QString itemRow, project->values(item)) {
869 t << itemRow << endl;
870 }
871 }
872 }
873}
874
875void SymbianMakefileGenerator::writeBldInfContent(QTextStream &t, bool addDeploymentExtension, const QString &iconFile)
876{
877 // Read user defined bld inf rules
878
879 QMap<QString, QStringList> userBldInfRules;
880 for (QMap<QString, QStringList>::iterator it = project->variables().begin(); it != project->variables().end(); ++it) {
881 if (it.key().startsWith(BLD_INF_RULES_BASE)) {
882 QString newKey = it.key().mid(sizeof(BLD_INF_RULES_BASE) - 1);
883 if (newKey.isEmpty()) {
884 fprintf(stderr, "Warning: Empty BLD_INF_RULES key encountered\n");
885 continue;
886 }
887 QStringList newValues;
888 QStringList values = it.value();
889 foreach(QString item, values) {
890 // If there is no stringlist defined for a rule, use rule name directly
891 // This is convenience for defining single line statements
892 if (project->values(item).isEmpty()) {
893 newValues << item;
894 } else {
895 foreach(QString itemRow, project->values(item)) {
896 newValues << itemRow;
897 }
898 }
899 }
900 userBldInfRules.insert(newKey, newValues);
901 }
902 }
903
904 // Add includes of subdirs bld.inf files
905
906 QString currentPath = qmake_getpwd();
907 QDir directory(currentPath);
908
909 const QStringList &subdirs = project->values("SUBDIRS");
910 foreach(QString item, subdirs) {
911 bool fromFile = false;
912 QString fixedItem;
913 if (!project->isEmpty(item + ".file")) {
914 fixedItem = project->first(item + ".file");
915 fromFile = true;
916 } else if (!project->isEmpty(item + ".subdir")) {
917 fixedItem = project->first(item + ".subdir");
918 fromFile = false;
919 } else {
920 fixedItem = item;
921 fromFile = item.endsWith(Option::pro_ext);
922 }
923
924 QString condition;
925 if (!project->isEmpty(item + ".condition"))
926 condition = project->first(item + ".condition");
927
928 QFileInfo subdir(fileInfo(fixedItem));
929 QString relativePath = directory.relativeFilePath(fixedItem);
930 QString fullProName = subdir.absoluteFilePath();
931 QString bldinfFilename;
932 QString subdirFileName;
933
934 if (fromFile) {
935 subdirFileName = subdir.completeBaseName();
936 } else {
937 subdirFileName = subdir.fileName();
938 }
939
940 if (subdir.isDir()) {
941 // Subdir is a regular project
942 bldinfFilename = relativePath + QString("/") + QString(BLD_INF_FILENAME);
943 fullProName += QString("/") + subdirFileName + Option::pro_ext;
944 } else {
945 // Subdir is actually a .pro file
946 if (relativePath.contains("/")) {
947 // .pro not in same directory as parent .pro
948 relativePath.remove(relativePath.lastIndexOf("/") + 1, relativePath.length());
949 bldinfFilename = relativePath;
950 } else {
951 // .pro and parent .pro in same directory
952 bldinfFilename = QString("./");
953 }
954 bldinfFilename += QString(BLD_INF_FILENAME ".") + subdirFileName;
955 }
956
957 QString uid = generate_uid(fullProName);
958 QString bldinfDefine = QString("BLD_INF_") + subdirFileName + QString("_") + uid;
959 bldinfDefine = bldinfDefine.toUpper();
960
961 // replace anything not alphanumeric with underscore
962 QRegExp replacementMask(DEFINE_REPLACE_REGEXP);
963 bldinfDefine.replace(replacementMask, QLatin1String("_"));
964
965 if (!condition.isEmpty())
966 t << "#if defined(" << condition << ")" << endl;
967
968 t << "#ifndef " << bldinfDefine << endl;
969 t << "\t#include \"" << bldinfFilename << "\"" << endl;
970 t << "#endif" << endl;
971
972 if (!condition.isEmpty())
973 t << "#endif" << endl;
974
975 }
976
977 // Add supported project platforms
978
979 t << endl << BLD_INF_TAG_PLATFORMS << endl << endl;
980 if (0 != project->values("SYMBIAN_PLATFORMS").size())
981 t << project->values("SYMBIAN_PLATFORMS").join(" ") << endl;
982
983 QStringList userItems = userBldInfRules.value(BLD_INF_TAG_PLATFORMS);
984 foreach(QString item, userItems)
985 t << item << endl;
986 userBldInfRules.remove(BLD_INF_TAG_PLATFORMS);
987 t << endl;
988
989 // Add project mmps and old style extension makefiles
990
991 QString mmpTag;
992 if (project->isActiveConfig(SYMBIAN_TEST_CONFIG))
993 mmpTag = QLatin1String(BLD_INF_TAG_TESTMMPFILES);
994 else
995 mmpTag = QLatin1String(BLD_INF_TAG_MMPFILES);
996
997 t << endl << mmpTag << endl << endl;
998
999 writeBldInfMkFilePart(t, addDeploymentExtension);
1000 if (targetType != TypeSubdirs)
1001 t << mmpFileName << endl;
1002
1003 userItems = userBldInfRules.value(mmpTag);
1004 foreach(QString item, userItems)
1005 t << item << endl;
1006 userBldInfRules.remove(mmpTag);
1007
1008 QString extensionTag;
1009 if (project->isActiveConfig(SYMBIAN_TEST_CONFIG))
1010 extensionTag = QLatin1String(BLD_INF_TAG_TESTEXTENSIONS);
1011 else
1012 extensionTag = QLatin1String(BLD_INF_TAG_EXTENSIONS);
1013
1014 t << endl << extensionTag << endl << endl;
1015
1016 // Generate extension rules
1017
1018 writeBldInfExtensionRulesPart(t, iconFile);
1019
1020 userItems = userBldInfRules.value(extensionTag);
1021 foreach(QString item, userItems)
1022 t << item << endl;
1023 userBldInfRules.remove(extensionTag);
1024
1025 // Add rest of the user defined content
1026
1027 for (QMap<QString, QStringList>::iterator it = userBldInfRules.begin(); it != userBldInfRules.end(); ++it) {
1028 t << endl << endl << it.key() << endl << endl;
1029 userItems = it.value();
1030 foreach(QString item, userItems)
1031 t << item << endl;
1032 }
1033}
1034
1035void SymbianMakefileGenerator::appendIfnotExist(QStringList &list, QString value)
1036{
1037 if (!list.contains(value))
1038 list += value;
1039}
1040
1041void SymbianMakefileGenerator::appendIfnotExist(QStringList &list, QStringList values)
1042{
1043 foreach(QString item, values)
1044 appendIfnotExist(list, item);
1045}
1046
1047
1048QString SymbianMakefileGenerator::removeTrailingPathSeparators(QString &file)
1049{
1050 QString ret = file;
1051 if (ret.endsWith(QDir::separator())) {
1052 ret.remove(ret.length() - 1, 1);
1053 }
1054
1055 return ret;
1056}
1057
1058void SymbianMakefileGenerator::generateCleanCommands(QTextStream& t,
1059 const QStringList& toClean,
1060 const QString& cmd,
1061 const QString& cmdOptions,
1062 const QString& itemPrefix,
1063 const QString& itemSuffix)
1064{
1065 for (int i = 0; i < toClean.size(); ++i) {
1066 QString item = toClean.at(i);
1067 item.prepend(itemPrefix).append(itemSuffix);
1068#if defined(Q_OS_WIN)
1069 t << "\t-@ if EXIST \"" << QDir::toNativeSeparators(item) << "\" ";
1070 t << cmd << " " << cmdOptions << " \"" << QDir::toNativeSeparators(item) << "\"" << endl;
1071#else
1072 t << "\t-if test -e " << QDir::toNativeSeparators(item) << "; then ";
1073 t << cmd << " " << cmdOptions << " " << QDir::toNativeSeparators(item) << "; fi" << endl;
1074#endif
1075 }
1076}
1077
1078void SymbianMakefileGenerator::generateDistcleanTargets(QTextStream& t)
1079{
1080 t << "dodistclean:" << endl;
1081 const QStringList &subdirs = project->values("SUBDIRS");
1082 foreach(QString item, subdirs) {
1083 bool fromFile = false;
1084 QString fixedItem;
1085 if (!project->isEmpty(item + ".file")) {
1086 fixedItem = project->first(item + ".file");
1087 fromFile = true;
1088 } else if (!project->isEmpty(item + ".subdir")) {
1089 fixedItem = project->first(item + ".subdir");
1090 fromFile = false;
1091 } else {
1092 fromFile = item.endsWith(Option::pro_ext);
1093 fixedItem = item;
1094 }
1095 QFileInfo fi(fileInfo(fixedItem));
1096 if (!fromFile) {
1097 t << "\t-$(MAKE) -f \"" << Option::fixPathToTargetOS(fi.absoluteFilePath() + "/Makefile") << "\" dodistclean" << endl;
1098 } else {
1099 QString itemName = fi.fileName();
1100 int extIndex = itemName.lastIndexOf(Option::pro_ext);
1101 if (extIndex)
1102 fixedItem = fi.absolutePath() + "/" + QString("Makefile.") + itemName.mid(0, extIndex);
1103 t << "\t-$(MAKE) -f \"" << Option::fixPathToTargetOS(fixedItem) << "\" dodistclean" << endl;
1104 }
1105
1106 }
1107
1108 generatedFiles << Option::fixPathToTargetOS(fileInfo(Option::output.fileName()).absoluteFilePath()); // bld.inf
1109 generatedFiles << project->values("QMAKE_INTERNAL_PRL_FILE"); // Add generated prl files for cleanup
1110 generatedFiles << project->values("QMAKE_DISTCLEAN"); // Add any additional files marked for distclean
1111 QStringList fixedFiles;
1112 QStringList fixedDirs;
1113 foreach(QString item, generatedFiles) {
1114 QString fixedItem = Option::fixPathToTargetOS(fileInfo(item).absoluteFilePath());
1115 if (!fixedFiles.contains(fixedItem)) {
1116 fixedFiles << fixedItem;
1117 }
1118 }
1119 foreach(QString item, generatedDirs) {
1120 QString fixedItem = Option::fixPathToTargetOS(fileInfo(item).absoluteFilePath());
1121 if (!fixedDirs.contains(fixedItem)) {
1122 fixedDirs << fixedItem;
1123 }
1124 }
1125 generateCleanCommands(t, fixedFiles, "$(DEL_FILE)", "", "", "");
1126 generateCleanCommands(t, fixedDirs, "$(DEL_DIR)", "", "", "");
1127 t << endl;
1128
1129 t << "distclean: clean dodistclean" << endl;
1130 t << endl;
1131}
1132
1133// Returns a string that can be used as a dependency to loc file on other targets
1134QString SymbianMakefileGenerator::generateLocFileTarget(QTextStream& t, const QString& locCmd)
1135{
1136 QString locFile;
1137 if (targetType == TypeExe && !project->isActiveConfig("no_icon")) {
1138 locFile = Option::fixPathToLocalOS(generateLocFileName());
1139 t << locFile << QLatin1String(": ") << project->values("SYMBIAN_MATCHED_TRANSLATIONS").join(" ") << endl;
1140 t << locCmd << endl;
1141 t << endl;
1142 locFile += QLatin1Char(' ');
1143 }
1144
1145 return locFile;
1146}
Note: See TracBrowser for help on using the repository browser.