summaryrefslogtreecommitdiffstats
path: root/qmake/generators/symbian/symbiancommon.cpp
blob: a36e4be3f490d088497abba42d5718afd09d0c33 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the qmake application of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "symbiancommon.h"

SymbianCommonGenerator::SymbianCommonGenerator(MakefileGenerator *generator)
    : generator(generator)
{
}

void SymbianCommonGenerator::init()
{
    QMakeProject *project = generator->project;
    fixedTarget = generator->escapeFilePath(generator->fileFixify(project->first("TARGET")));
    fixedTarget = removePathSeparators(fixedTarget);
    removeSpecialCharacters(fixedTarget);

    // This should not be empty since the mkspecs are supposed to set it if missing.
    uid3 = project->first("TARGET.UID3").trimmed();

    if ((project->values("TEMPLATE")).contains("app"))
        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"))
            targetType = TypeLib;
        else if (project->values("CONFIG").contains("plugin"))
            targetType = TypePlugin;
        else
            targetType = TypeDll;
    } else {
        targetType = TypeSubdirs;
    }

    // UID is valid as either hex or decimal, so just convert it to number and back to hex
    // to get proper string for private dir
    bool conversionOk = false;
    uint uidNum = uid3.toUInt(&conversionOk, 0);

    if (!conversionOk) {
        fprintf(stderr, "Error: Invalid UID \"%s\".\n", uid3.toUtf8().constData());
    } else {
        privateDirUid.setNum(uidNum, 16);
        while (privateDirUid.length() < 8)
            privateDirUid.insert(0, QLatin1Char('0'));
    }
}

bool SymbianCommonGenerator::containsStartWithItem(const QChar &c, const QStringList& src)
{
    bool result = false;
    foreach(QString str, src) {
        if (str.startsWith(c)) {
            result =  true;
            break;
        }
    }
    return result;
}

void SymbianCommonGenerator::removeSpecialCharacters(QString& str)
{
    // When modifying this method check also application_icon.prf
    str.replace(QString("/"), QString("_"));
    str.replace(QString("\\"), QString("_"));
    str.replace(QString("-"), QString("_"));
    str.replace(QString(":"), QString("_"));
    str.replace(QString("."), QString("_"));
    str.replace(QString(" "), QString("_"));
}

void SymbianCommonGenerator::generatePkgFile(const QString &iconFile, DeploymentList &depList, bool epocBuild)
{
    QMakeProject *project = generator->project;
    QString pkgFilename = QString("%1_template.%2")
                          .arg(fixedTarget)
                          .arg("pkg");
    QFile pkgFile(pkgFilename);
    if (!pkgFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
        PRINT_FILE_CREATE_ERROR(pkgFilename);
        return;
    }

    generatedFiles << pkgFile.fileName();

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

    // Construct QStringList from pkg_prerules since we need search it before printed to file
    QStringList rawPkgPreRules;
    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;
            } else {
                foreach(QString pkgrule, pkgrulesValue) {
                    rawPkgPreRules << pkgrule;
                }
            }
        }
    }

    // Apply some defaults if specific data does not exist in PKG pre-rules

    if (!containsStartWithItem('&', rawPkgPreRules)) {
        // language, (*** hardcoded to english atm, should be parsed from TRANSLATIONS)
        t << "; Language" << endl;
        t << "&EN" << endl << endl;
    } else {
        // 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");
    }

    // name of application, UID and version
    QString applicationVersion = project->first("VERSION").isEmpty() ? "1,0,0" : project->first("VERSION").replace('.', ',');

    if (!containsStartWithItem('#', rawPkgPreRules)) {
        QString visualTarget = generator->escapeFilePath(generator->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;
    }

    // Localized vendor name
    if (!containsStartWithItem('%', rawPkgPreRules)) {
        t << "; Localised Vendor name" << endl;
        t << "%{\"Vendor\"}" << endl << endl;
    }

    // Unique vendor name
    if (!containsStartWithItem(':', rawPkgPreRules)) {
        t << "; Unique Vendor name" << endl;
        t << ":\"Vendor\"" << endl << endl;
    }

    // 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;
        foreach(QString item, rawPkgPreRules) {
            t << item << endl;
        }
        t << endl;
    }

    // Install paths on the phone *** should be dynamic at some point
    QString installPathBin = "!:\\sys\\bin";
    QString installPathResource = "!:\\resource\\apps";
    QString installPathRegResource = "!:\\private\\10003a3f\\import\\apps";

    // Find location of builds
    QString epocReleasePath = QString("%1epoc32/release/$(PLATFORM)/$(TARGET)")
                              .arg(epocRoot());


    if (targetType == TypeExe) {
        // deploy .exe file
        t << "; Executable and default resource files" << endl;
        QString exeFile = fixedTarget + ".exe";
        t << QString("\"%1/%2\"    - \"%3\\%4\"")
             .arg(epocReleasePath)
             .arg(exeFile)
             .arg(installPathBin)
             .arg(exeFile) << endl;

        // deploy rsc & reg_rsc file
        if (!project->values("CONFIG").contains("no_icon", Qt::CaseInsensitive)) {
            t << QString("\"%1epoc32/data/z/resource/apps/%2\"    - \"%3\\%4\"")
                 .arg(epocRoot())
                 .arg(fixedTarget + ".rsc")
                 .arg(installPathResource)
                 .arg(fixedTarget + ".rsc") << endl;

            t << QString("\"%1epoc32/data/z/private/10003a3f/import/apps/%2\"    - \"%3\\%4\"")
                 .arg(epocRoot())
                 .arg(fixedTarget + "_reg.rsc")
                 .arg(installPathRegResource)
                 .arg(fixedTarget + "_reg.rsc") << endl;

            if (!iconFile.isEmpty())  {
                t << QString("\"%1epoc32/data/z%2\"    - \"!:%3\"")
                     .arg(epocRoot())
                     .arg(iconFile)
                     .arg(QDir::toNativeSeparators(iconFile)) << endl << endl;
            }
        }
    }

    // deploy any additional DEPLOYMENT  files
    QString remoteTestPath;
    remoteTestPath = QString("!:\\private\\%1").arg(privateDirUid);

    initProjectDeploySymbian(project, depList, remoteTestPath, true, epocBuild, "$(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;
    }
    t << endl;

    // PKG post-rules - these are added after actual file installations i.e. SIS package body
    t << "; Manual PKG post-rules from PRO files" << endl;
    foreach(QString deploymentItem, project->values("DEPLOYMENT")) {
        foreach(QString pkgrulesItem, project->values(deploymentItem + ".pkg_postrules")) {
            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 statements
            if (pkgrulesValue.isEmpty()) {
                t << pkgrulesItem << endl;
            } else {
                foreach(QString pkgrule, pkgrulesValue) {
                    t << pkgrule << endl;
                }
            }
            t << endl;
        }
    }
}

QString SymbianCommonGenerator::removePathSeparators(QString &file)
{
    QString ret = file;
    while (ret.indexOf(QDir::separator()) > 0) {
        ret.remove(0, ret.indexOf(QDir::separator()) + 1);
    }

    return ret;
}