source: trunk/qmake/generators/symbian/initprojectdeploy_symbian.cpp@ 674

Last change on this file since 674 was 651, checked in by Dmitry A. Kuminov, 16 years ago

trunk: Merged in qt 4.6.2 sources.

  • Property svn:eol-style set to native
File size: 17.3 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
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 [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "initprojectdeploy_symbian.h"
43#include <QDirIterator>
44#include <project.h>
45#include <qxmlstream.h>
46#include <qsettings.h>
47#include <qdebug.h>
48
49#define SYSBIN_DIR "\\sys\\bin"
50
51#define SUFFIX_DLL "dll"
52#define SUFFIX_EXE "exe"
53#define SUFFIX_QTPLUGIN "qtplugin"
54
55static void fixEpocRootStr(QString& path)
56{
57 path.replace("\\", "/");
58
59 if (path.size() > 1 && path[1] == QChar(':')) {
60 path = path.mid(2);
61 }
62
63 if (!path.size() || path[path.size()-1] != QChar('/')) {
64 path += QChar('/');
65 }
66}
67
68#define SYMBIAN_SDKS_KEY "HKEY_LOCAL_MACHINE\\Software\\Symbian\\EPOC SDKs"
69
70static QString epocRootStr;
71
72QString epocRoot()
73{
74 if (!epocRootStr.isEmpty()) {
75 return epocRootStr;
76 }
77
78 // First, check the env variable
79 epocRootStr = qgetenv("EPOCROOT");
80
81 if (epocRootStr.isEmpty()) {
82 // No EPOCROOT set, check the default device
83 // First check EPOCDEVICE env variable
84 QString defaultDevice = qgetenv("EPOCDEVICE");
85
86 // Check the windows registry via QSettings for devices.xml path
87 QSettings settings(SYMBIAN_SDKS_KEY, QSettings::NativeFormat);
88 QString devicesXmlPath = settings.value("CommonPath").toString();
89
90 if (!devicesXmlPath.isEmpty()) {
91 // Parse xml for correct device
92 devicesXmlPath += "/devices.xml";
93 QFile devicesFile(devicesXmlPath);
94 if (devicesFile.open(QIODevice::ReadOnly)) {
95 QXmlStreamReader xml(&devicesFile);
96 while (!xml.atEnd()) {
97 xml.readNext();
98 if (xml.isStartElement() && xml.name() == "devices") {
99 if (xml.attributes().value("version") == "1.0") {
100 // Look for correct device
101 while (!(xml.isEndElement() && xml.name() == "devices") && !xml.atEnd()) {
102 xml.readNext();
103 if (xml.isStartElement() && xml.name() == "device") {
104 if ((defaultDevice.isEmpty() && xml.attributes().value("default") == "yes") ||
105 (!defaultDevice.isEmpty() && (xml.attributes().value("id").toString() + QString(":") + xml.attributes().value("name").toString()) == defaultDevice)) {
106 // Found the correct device
107 while (!(xml.isEndElement() && xml.name() == "device") && !xml.atEnd()) {
108 xml.readNext();
109 if (xml.isStartElement() && xml.name() == "epocroot") {
110 epocRootStr = xml.readElementText();
111 fixEpocRootStr(epocRootStr);
112 return epocRootStr;
113 }
114 }
115 xml.raiseError("No epocroot element found");
116 }
117 }
118 }
119 } else {
120 xml.raiseError("Invalid 'devices' element version");
121 }
122 }
123 }
124 if (xml.hasError()) {
125 fprintf(stderr, "ERROR: \"%s\" when parsing devices.xml\n", qPrintable(xml.errorString()));
126 }
127 } else {
128 fprintf(stderr, "Could not open devices.xml (%s)\n", qPrintable(devicesXmlPath));
129 }
130 } else {
131 fprintf(stderr, "Could not retrieve " SYMBIAN_SDKS_KEY " setting\n");
132 }
133
134 fprintf(stderr, "Failed to determine epoc root.\n");
135 if (!defaultDevice.isEmpty())
136 fprintf(stderr, "The device indicated by EPOCDEVICE environment variable (%s) could not be found.\n", qPrintable(defaultDevice));
137 fprintf(stderr, "Either set EPOCROOT or EPOCDEVICE environment variable to a valid value, or provide a default Symbian device.\n");
138
139 // No valid device found; set epocroot to "/"
140 epocRootStr = QLatin1String("/");
141 }
142
143 fixEpocRootStr(epocRootStr);
144 return epocRootStr;
145}
146
147
148static bool isPlugin(const QFileInfo& info, const QString& devicePath)
149{
150 // Libraries are plugins if deployment path is something else than
151 // SYSBIN_DIR with or without drive letter
152 if (0 == info.suffix().compare(QLatin1String(SUFFIX_DLL), Qt::CaseInsensitive) &&
153 (devicePath.size() < 8 ||
154 (0 != devicePath.compare(QLatin1String(SYSBIN_DIR), Qt::CaseInsensitive) &&
155 0 != devicePath.mid(1).compare(QLatin1String(":" SYSBIN_DIR), Qt::CaseInsensitive)))) {
156 return true;
157 } else {
158 return false;
159 }
160}
161
162static bool isBinary(const QFileInfo& info)
163{
164 if (0 == info.suffix().compare(QLatin1String(SUFFIX_DLL), Qt::CaseInsensitive) ||
165 0 == info.suffix().compare(QLatin1String(SUFFIX_EXE), Qt::CaseInsensitive)) {
166 return true;
167 } else {
168 return false;
169 }
170}
171
172static void createPluginStub(const QFileInfo& info,
173 const QString& devicePath,
174 DeploymentList &deploymentList,
175 QStringList& generatedDirs,
176 QStringList& generatedFiles)
177{
178 QDir().mkpath(QLatin1String(PLUGIN_STUB_DIR "\\"));
179 if (!generatedDirs.contains(PLUGIN_STUB_DIR))
180 generatedDirs << PLUGIN_STUB_DIR;
181 // Plugin stubs must have different name from the actual plugins, because
182 // the toolchain for creating ROM images cannot handle non-binary .dll files properly.
183 QFile stubFile(QLatin1String(PLUGIN_STUB_DIR "\\") + info.completeBaseName() + "." SUFFIX_QTPLUGIN);
184 if (stubFile.open(QIODevice::WriteOnly)) {
185 if (!generatedFiles.contains(stubFile.fileName()))
186 generatedFiles << stubFile.fileName();
187 QTextStream t(&stubFile);
188 // Add note to stub so that people will not wonder what it is.
189 // Creation date is added to make new stub to deploy always to
190 // force plugin cache miss when loading plugins.
191 t << "This file is a Qt plugin stub file. The real Qt plugin is located in " SYSBIN_DIR ". Created:" << QDateTime::currentDateTime().toString(Qt::ISODate) << "\n";
192 } else {
193 fprintf(stderr, "cannot deploy \"%s\" because of plugin stub file creation failed\n", info.fileName().toLatin1().constData());
194 }
195 QFileInfo stubInfo(stubFile);
196 deploymentList.append(CopyItem(Option::fixPathToLocalOS(stubInfo.absoluteFilePath()),
197 Option::fixPathToLocalOS(devicePath + "\\" + stubInfo.fileName())));
198}
199
200QString generate_uid(const QString& target)
201{
202 static QMap<QString, QString> targetToUid;
203
204 QString tmp = targetToUid[target];
205
206 if (!tmp.isEmpty()) {
207 return tmp;
208 }
209
210 unsigned long hash = 5381;
211 int c;
212
213 for (int i = 0; i < target.size(); ++i) {
214 c = target.at(i).toAscii();
215 hash ^= c + ((c - i) << i % 20) + ((c + i) << (i + 5) % 20) + ((c - 2 * i) << (i + 10) % 20) + ((c + 2 * i) << (i + 15) % 20);
216 }
217
218 tmp.setNum(hash, 16);
219 for (int i = tmp.size(); i < 8; ++i)
220 tmp.prepend("0");
221
222 targetToUid[target] = tmp;
223
224 return tmp;
225}
226
227// UIDs starting with 0xE are test UIDs in symbian
228QString generate_test_uid(const QString& target)
229{
230 QString tmp = generate_uid(target);
231 tmp.replace(0, 1, "E");
232 tmp.prepend("0x");
233
234 return tmp;
235}
236
237
238void initProjectDeploySymbian(QMakeProject* project,
239 DeploymentList &deploymentList,
240 const QString &testPath,
241 bool deployBinaries,
242 const QString &platform,
243 const QString &build,
244 QStringList& generatedDirs,
245 QStringList& generatedFiles)
246{
247 QString targetPath = project->values("deploy.path").join(" ");
248 if (targetPath.isEmpty())
249 targetPath = testPath;
250 if (targetPath.endsWith("/") || targetPath.endsWith("\\"))
251 targetPath = targetPath.mid(0, targetPath.size() - 1);
252
253 bool targetPathHasDriveLetter = false;
254 if (targetPath.size() > 1) {
255 targetPathHasDriveLetter = targetPath.at(1) == QLatin1Char(':');
256 }
257 QString deploymentDrive = targetPathHasDriveLetter ? targetPath.left(2) : QLatin1String("c:");
258
259 foreach(QString item, project->values("DEPLOYMENT")) {
260 QString devicePath = project->first(item + ".path");
261 if (!deployBinaries
262 && !devicePath.isEmpty()
263 && (0 == devicePath.compare(project->values("APP_RESOURCE_DIR").join(""), Qt::CaseInsensitive)
264 || 0 == devicePath.compare(project->values("REG_RESOURCE_IMPORT_DIR").join(""), Qt::CaseInsensitive))) {
265 // Do not deploy resources in emulator builds, as that seems to cause conflicts
266 // If there is ever a real need to deploy pre-built resources for emulator,
267 // BLD_INF_RULES.prj_exports can be used as a workaround.
268 continue;
269 }
270
271 bool devicePathHasDriveLetter = false;
272 if (devicePath.size() > 1) {
273 devicePathHasDriveLetter = devicePath.at(1) == QLatin1Char(':');
274 }
275
276 if (devicePath.isEmpty() || devicePath == QLatin1String(".")) {
277 devicePath = targetPath;
278 }
279 // check if item.path is relative (! either / or \)
280 else if (!(devicePath.at(0) == QLatin1Char('/')
281 || devicePath.at(0) == QLatin1Char('\\')
282 || devicePathHasDriveLetter)) {
283 // create output path
284 devicePath = Option::fixPathToLocalOS(QDir::cleanPath(targetPath + QLatin1Char('\\') + devicePath));
285 } else {
286 if (0 == platform.compare(QLatin1String("winscw"), Qt::CaseInsensitive)) {
287 if (devicePathHasDriveLetter) {
288 devicePath = epocRoot() + "epoc32\\winscw\\" + devicePath.remove(1, 1);
289 } else {
290 devicePath = epocRoot() + "epoc32\\winscw\\c" + devicePath;
291 }
292 } else {
293 // Drive letter needed if targetpath contains one and it is not already in
294 if (targetPathHasDriveLetter && !devicePathHasDriveLetter) {
295 devicePath = deploymentDrive + devicePath;
296 }
297 }
298 }
299
300 devicePath.replace(QLatin1String("/"), QLatin1String("\\"));
301
302 if (!deployBinaries &&
303 0 == devicePath.right(8).compare(QLatin1String(SYSBIN_DIR), Qt::CaseInsensitive)) {
304 // Skip deploying to SYSBIN_DIR for anything but binary deployments
305 // Note: Deploying pre-built binaries also follow this rule, so emulator builds
306 // will not get those deployed. Since there is no way to differentiate currently
307 // between pre-built binaries for emulator and HW anyway, this is not a major issue.
308 continue;
309 }
310
311 foreach(QString source, project->values(item + ".sources")) {
312 source = Option::fixPathToLocalOS(source);
313 QString nameFilter;
314 QFileInfo info(source);
315 QString searchPath;
316 bool dirSearch = false;
317
318 if (info.isDir()) {
319 nameFilter = QLatin1String("*");
320 searchPath = info.absoluteFilePath();
321 dirSearch = true;
322 } else {
323 if (info.exists() || source.indexOf('*') != -1) {
324 nameFilter = source.split('\\').last();
325 searchPath = info.absolutePath();
326 } else {
327 // Entry was not found. That is ok if it is a binary, since those do not necessarily yet exist.
328 // Dlls need to be processed even when not deploying binaries for the stubs
329 if (isBinary(info)) {
330 if (deployBinaries) {
331 // Executables and libraries are deployed to \sys\bin
332 QFileInfo releasePath(epocRoot() + "epoc32\\release\\" + platform + "\\" + build + "\\");
333 if(devicePathHasDriveLetter) {
334 deploymentList.append(CopyItem(Option::fixPathToLocalOS(releasePath.absolutePath() + "\\" + info.fileName(), false, true),
335 Option::fixPathToLocalOS(devicePath.left(2) + QLatin1String(SYSBIN_DIR "\\") + info.fileName())));
336 } else {
337 deploymentList.append(CopyItem(Option::fixPathToLocalOS(releasePath.absolutePath() + "\\" + info.fileName(), false, true),
338 Option::fixPathToLocalOS(deploymentDrive + QLatin1String(SYSBIN_DIR "\\") + info.fileName())));
339 }
340 }
341 if (isPlugin(info, devicePath)) {
342 createPluginStub(info, devicePath, deploymentList, generatedDirs, generatedFiles);
343 continue;
344 }
345 } else {
346 // Generate deployment even if file doesn't exist, as this may be the case
347 // when generating .pkg files.
348 deploymentList.append(CopyItem(Option::fixPathToLocalOS(info.absoluteFilePath()),
349 Option::fixPathToLocalOS(devicePath + "\\" + info.fileName())));
350 continue;
351 }
352 }
353 }
354
355 int pathSize = info.absolutePath().size();
356 QDirIterator iterator(searchPath, QStringList() << nameFilter
357 , QDir::Files | QDir::NoDotAndDotDot | QDir::NoSymLinks
358 , dirSearch ? QDirIterator::Subdirectories : QDirIterator::NoIteratorFlags);
359
360 while (iterator.hasNext()) {
361 iterator.next();
362 QFileInfo iteratorInfo(iterator.filePath());
363 QString absoluteItemPath = Option::fixPathToLocalOS(iteratorInfo.absolutePath());
364 int diffSize = absoluteItemPath.size() - pathSize;
365
366 if (!iteratorInfo.isDir()) {
367 if (isPlugin(iterator.fileInfo(), devicePath)) {
368 // This deploys pre-built plugins. Other pre-built binaries will deploy normally,
369 // as they have SYSBIN_DIR target path.
370 if (deployBinaries) {
371 deploymentList.append(CopyItem(Option::fixPathToLocalOS(absoluteItemPath + "\\" + iterator.fileName()),
372 Option::fixPathToLocalOS(deploymentDrive + QLatin1String(SYSBIN_DIR "\\") + iterator.fileName())));
373 }
374 createPluginStub(info, devicePath + "\\" + absoluteItemPath.right(diffSize), deploymentList, generatedDirs, generatedFiles);
375 continue;
376 } else {
377 deploymentList.append(CopyItem(Option::fixPathToLocalOS(absoluteItemPath + "\\" + iterator.fileName()),
378 Option::fixPathToLocalOS(devicePath + "\\" + absoluteItemPath.right(diffSize) + "\\" + iterator.fileName())));
379 }
380 }
381 }
382 }
383 }
384}
Note: See TracBrowser for help on using the repository browser.