1 | /****************************************************************************
|
---|
2 | **
|
---|
3 | ** Copyright (C) 2011 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 | // Included from tools/shared
|
---|
50 | #include <symbian/epocroot_p.h>
|
---|
51 |
|
---|
52 | #define SYSBIN_DIR "/sys/bin"
|
---|
53 | #define HW_Z_DIR "epoc32/data/z"
|
---|
54 |
|
---|
55 | #define SUFFIX_DLL "dll"
|
---|
56 | #define SUFFIX_EXE "exe"
|
---|
57 | #define SUFFIX_QTPLUGIN "qtplugin"
|
---|
58 |
|
---|
59 | static QString fixPathToEpocOS(const QString &src)
|
---|
60 | {
|
---|
61 | QString ret = Option::fixPathToTargetOS(src);
|
---|
62 |
|
---|
63 | bool pathHasDriveLetter = false;
|
---|
64 | if (ret.size() > 1)
|
---|
65 | pathHasDriveLetter = (ret.at(1) == QLatin1Char(':'));
|
---|
66 |
|
---|
67 | return pathHasDriveLetter ? ret.replace('/', '\\') : QDir::toNativeSeparators(ret);
|
---|
68 | }
|
---|
69 |
|
---|
70 | static bool isPlugin(const QFileInfo& info, const QString& devicePath)
|
---|
71 | {
|
---|
72 | // Libraries are plugins if deployment path is something else than
|
---|
73 | // SYSBIN_DIR with or without drive letter
|
---|
74 | if (0 == info.suffix().compare(QLatin1String(SUFFIX_DLL), Qt::CaseInsensitive)
|
---|
75 | && (devicePath.size() < 8
|
---|
76 | || (0 != devicePath.compare(QLatin1String(SYSBIN_DIR), Qt::CaseInsensitive)
|
---|
77 | && 0 != devicePath.mid(1).compare(QLatin1String(":" SYSBIN_DIR), Qt::CaseInsensitive)
|
---|
78 | && 0 != devicePath.compare(qt_epocRoot() + QLatin1String(HW_Z_DIR SYSBIN_DIR))))) {
|
---|
79 | return true;
|
---|
80 | } else {
|
---|
81 | return false;
|
---|
82 | }
|
---|
83 | }
|
---|
84 |
|
---|
85 | static bool isBinary(const QFileInfo& info)
|
---|
86 | {
|
---|
87 | if (0 == info.suffix().compare(QLatin1String(SUFFIX_DLL), Qt::CaseInsensitive) ||
|
---|
88 | 0 == info.suffix().compare(QLatin1String(SUFFIX_EXE), Qt::CaseInsensitive)) {
|
---|
89 | return true;
|
---|
90 | } else {
|
---|
91 | return false;
|
---|
92 | }
|
---|
93 | }
|
---|
94 |
|
---|
95 | static void createPluginStub(const QFileInfo& info,
|
---|
96 | const QString& devicePath,
|
---|
97 | DeploymentList &deploymentList,
|
---|
98 | QStringList& generatedDirs,
|
---|
99 | QStringList& generatedFiles)
|
---|
100 | {
|
---|
101 | QString pluginStubDir = Option::output_dir + QLatin1Char('/') + QLatin1String(PLUGIN_STUB_DIR);
|
---|
102 | QDir().mkpath(pluginStubDir);
|
---|
103 | if (!generatedDirs.contains(pluginStubDir))
|
---|
104 | generatedDirs << pluginStubDir;
|
---|
105 | // Plugin stubs must have different name from the actual plugins, because
|
---|
106 | // the toolchain for creating ROM images cannot handle non-binary .dll files properly.
|
---|
107 | QFile stubFile(pluginStubDir + QLatin1Char('/') + info.completeBaseName() + QLatin1Char('.') + QLatin1String(SUFFIX_QTPLUGIN));
|
---|
108 | if (stubFile.open(QIODevice::WriteOnly)) {
|
---|
109 | if (!generatedFiles.contains(stubFile.fileName()))
|
---|
110 | generatedFiles << stubFile.fileName();
|
---|
111 | QTextStream t(&stubFile);
|
---|
112 | // Add note to stub so that people will not wonder what it is.
|
---|
113 | // Creation date is added to make new stub to deploy always to
|
---|
114 | // force plugin cache miss when loading plugins.
|
---|
115 | 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";
|
---|
116 | } else {
|
---|
117 | fprintf(stderr, "cannot deploy \"%s\" because of plugin stub file creation failed\n", info.fileName().toLatin1().constData());
|
---|
118 | }
|
---|
119 | QFileInfo stubInfo(stubFile);
|
---|
120 | deploymentList.append(CopyItem(Option::fixPathToLocalOS(stubInfo.absoluteFilePath()),
|
---|
121 | fixPathToEpocOS(devicePath + "/" + stubInfo.fileName())));
|
---|
122 | }
|
---|
123 |
|
---|
124 | QString generate_uid(const QString& target)
|
---|
125 | {
|
---|
126 | static QMap<QString, QString> targetToUid;
|
---|
127 |
|
---|
128 | QString tmp = targetToUid[target];
|
---|
129 |
|
---|
130 | if (!tmp.isEmpty()) {
|
---|
131 | return tmp;
|
---|
132 | }
|
---|
133 |
|
---|
134 | quint32 hash = 5381;
|
---|
135 | int c;
|
---|
136 |
|
---|
137 | for (int i = 0; i < target.size(); ++i) {
|
---|
138 | c = target.at(i).toAscii();
|
---|
139 | hash ^= c + ((c - i) << i % 20) + ((c + i) << (i + 5) % 20) + ((c - 2 * i) << (i + 10) % 20) + ((c + 2 * i) << (i + 15) % 20);
|
---|
140 | }
|
---|
141 |
|
---|
142 | tmp.setNum(hash, 16);
|
---|
143 | for (int i = tmp.size(); i < 8; ++i)
|
---|
144 | tmp.prepend("0");
|
---|
145 |
|
---|
146 | targetToUid[target] = tmp;
|
---|
147 |
|
---|
148 | return tmp;
|
---|
149 | }
|
---|
150 |
|
---|
151 | // UIDs starting with 0xE are test UIDs in symbian
|
---|
152 | QString generate_test_uid(const QString& target)
|
---|
153 | {
|
---|
154 | QString tmp = generate_uid(target);
|
---|
155 | tmp.replace(0, 1, "E");
|
---|
156 | tmp.prepend("0x");
|
---|
157 |
|
---|
158 | return tmp;
|
---|
159 | }
|
---|
160 |
|
---|
161 |
|
---|
162 | void initProjectDeploySymbian(QMakeProject* project,
|
---|
163 | DeploymentList &deploymentList,
|
---|
164 | const QString &testPath,
|
---|
165 | bool deployBinaries,
|
---|
166 | bool epocBuild,
|
---|
167 | const QString &platform,
|
---|
168 | const QString &build,
|
---|
169 | QStringList& generatedDirs,
|
---|
170 | QStringList& generatedFiles)
|
---|
171 | {
|
---|
172 | QString targetPath = project->values("deploy.path").join(" ");
|
---|
173 | if (targetPath.isEmpty())
|
---|
174 | targetPath = testPath;
|
---|
175 | if (targetPath.endsWith("/") || targetPath.endsWith("\\"))
|
---|
176 | targetPath = targetPath.mid(0, targetPath.size() - 1);
|
---|
177 |
|
---|
178 | bool targetPathHasDriveLetter = false;
|
---|
179 | if (targetPath.size() > 1) {
|
---|
180 | targetPathHasDriveLetter = targetPath.at(1) == QLatin1Char(':');
|
---|
181 | }
|
---|
182 |
|
---|
183 | QString deploymentDrive;
|
---|
184 | if (0 == platform.compare(QLatin1String(ROM_DEPLOYMENT_PLATFORM))) {
|
---|
185 | deploymentDrive = qt_epocRoot() + HW_Z_DIR;
|
---|
186 | } else {
|
---|
187 | deploymentDrive = targetPathHasDriveLetter ? targetPath.left(2) : QLatin1String("c:");
|
---|
188 | }
|
---|
189 |
|
---|
190 | foreach(QString item, project->values("DEPLOYMENT")) {
|
---|
191 | QString devicePath = project->first(item + ".path");
|
---|
192 | QString devicePathWithoutDrive = devicePath;
|
---|
193 |
|
---|
194 | bool devicePathHasDriveLetter = false;
|
---|
195 | if (devicePath.size() > 1) {
|
---|
196 | devicePathHasDriveLetter = devicePath.at(1) == QLatin1Char(':');
|
---|
197 | }
|
---|
198 |
|
---|
199 | // Sometimes devicePath can contain disk but APP_RESOURCE_DIR does not,
|
---|
200 | // so remove the drive letter for comparison purposes.
|
---|
201 | if (devicePathHasDriveLetter)
|
---|
202 | {
|
---|
203 | devicePathWithoutDrive.remove(0,2);
|
---|
204 | }
|
---|
205 | if (!deployBinaries
|
---|
206 | && 0 != platform.compare(QLatin1String(ROM_DEPLOYMENT_PLATFORM))
|
---|
207 | && !devicePathWithoutDrive.isEmpty()
|
---|
208 | && (0 == devicePathWithoutDrive.compare(project->values("APP_RESOURCE_DIR").join(""), Qt::CaseInsensitive)
|
---|
209 | || 0 == devicePathWithoutDrive.compare(project->values("REG_RESOURCE_IMPORT_DIR").join(""), Qt::CaseInsensitive))) {
|
---|
210 | // Do not deploy resources in emulator builds, as that seems to cause conflicts
|
---|
211 | // If there is ever a real need to deploy pre-built resources for emulator,
|
---|
212 | // BLD_INF_RULES.prj_exports can be used as a workaround.
|
---|
213 | continue;
|
---|
214 | }
|
---|
215 |
|
---|
216 | if (devicePath.isEmpty() || devicePath == QLatin1String(".")) {
|
---|
217 | devicePath = targetPath;
|
---|
218 | }
|
---|
219 | // check if item.path is relative (! either / or \)
|
---|
220 | else if (!(devicePath.at(0) == QLatin1Char('/')
|
---|
221 | || devicePath.at(0) == QLatin1Char('\\')
|
---|
222 | || devicePathHasDriveLetter)) {
|
---|
223 | // Create output path
|
---|
224 | devicePath = Option::fixPathToLocalOS(QDir::cleanPath(targetPath + QLatin1Char('/') + devicePath));
|
---|
225 | } else {
|
---|
226 | if (0 == platform.compare(QLatin1String(EMULATOR_DEPLOYMENT_PLATFORM))) {
|
---|
227 | if (devicePathHasDriveLetter) {
|
---|
228 | devicePath = qt_epocRoot() + "epoc32/winscw/" + devicePath.remove(1, 1);
|
---|
229 | } else {
|
---|
230 | devicePath = qt_epocRoot() + "epoc32/winscw/c" + devicePath;
|
---|
231 | }
|
---|
232 | } else {
|
---|
233 | if (devicePathHasDriveLetter
|
---|
234 | && 0 == platform.compare(QLatin1String(ROM_DEPLOYMENT_PLATFORM))) {
|
---|
235 | devicePath.remove(0,2);
|
---|
236 | }
|
---|
237 | if (0 == platform.compare(QLatin1String(ROM_DEPLOYMENT_PLATFORM))
|
---|
238 | || (!devicePathHasDriveLetter && targetPathHasDriveLetter)) {
|
---|
239 | devicePath = deploymentDrive + devicePath;
|
---|
240 | }
|
---|
241 | }
|
---|
242 | }
|
---|
243 |
|
---|
244 | devicePath.replace(QLatin1String("\\"), QLatin1String("/"));
|
---|
245 |
|
---|
246 | if (!deployBinaries
|
---|
247 | && 0 == devicePath.right(8).compare(QLatin1String(SYSBIN_DIR), Qt::CaseInsensitive)
|
---|
248 | && 0 != platform.compare(QLatin1String(ROM_DEPLOYMENT_PLATFORM))) {
|
---|
249 | // Skip deploying to SYSBIN_DIR for anything but binary deployments
|
---|
250 | // Note: Deploying pre-built binaries also follow this rule, so emulator builds
|
---|
251 | // will not get those deployed. Since there is no way to differentiate currently
|
---|
252 | // between pre-built binaries for emulator and HW anyway, this is not a major issue.
|
---|
253 | continue;
|
---|
254 | }
|
---|
255 |
|
---|
256 | QStringList flags = project->values(item + ".flags");
|
---|
257 |
|
---|
258 | foreach(QString source, project->values(item + ".sources")) {
|
---|
259 | source = Option::fixPathToLocalOS(source);
|
---|
260 | QString nameFilter;
|
---|
261 | QFileInfo info(source);
|
---|
262 | QString searchPath;
|
---|
263 | bool dirSearch = false;
|
---|
264 |
|
---|
265 | if (info.isDir()) {
|
---|
266 | nameFilter = QLatin1String("*");
|
---|
267 | searchPath = info.absoluteFilePath();
|
---|
268 | dirSearch = true;
|
---|
269 | } else {
|
---|
270 | if (info.exists() || source.indexOf('*') != -1) {
|
---|
271 | nameFilter = source.split(QDir::separator()).last();
|
---|
272 | searchPath = info.absolutePath();
|
---|
273 | } else {
|
---|
274 | // Entry was not found. That is ok if it is a binary, since those do not necessarily yet exist.
|
---|
275 | // Dlls need to be processed even when not deploying binaries for the stubs
|
---|
276 | if (isBinary(info)) {
|
---|
277 | if (deployBinaries) {
|
---|
278 | // Executables and libraries are deployed to \sys\bin
|
---|
279 | QFileInfo targetPath;
|
---|
280 | if (epocBuild)
|
---|
281 | targetPath.setFile(qt_epocRoot() + "epoc32/release/" + platform + "/" + build + "/");
|
---|
282 | else
|
---|
283 | targetPath.setFile(info.path() + QDir::separator());
|
---|
284 | if(devicePathHasDriveLetter) {
|
---|
285 | deploymentList.append(CopyItem(
|
---|
286 | Option::fixPathToLocalOS(targetPath.absolutePath() + "/" + info.fileName(),
|
---|
287 | false, true),
|
---|
288 | fixPathToEpocOS(devicePath.left(2) + QLatin1String(SYSBIN_DIR "/")
|
---|
289 | + info.fileName()),
|
---|
290 | flags));
|
---|
291 | } else {
|
---|
292 | deploymentList.append(CopyItem(
|
---|
293 | Option::fixPathToLocalOS(targetPath.absolutePath() + "/" + info.fileName(),
|
---|
294 | false, true),
|
---|
295 | fixPathToEpocOS(deploymentDrive + QLatin1String("/" SYSBIN_DIR "/")
|
---|
296 | + info.fileName()),
|
---|
297 | flags));
|
---|
298 | }
|
---|
299 | }
|
---|
300 | if (isPlugin(info, devicePath)) {
|
---|
301 | createPluginStub(info, devicePath, deploymentList, generatedDirs, generatedFiles);
|
---|
302 | continue;
|
---|
303 | }
|
---|
304 | } else {
|
---|
305 | // Generate deployment even if file doesn't exist, as this may be the case
|
---|
306 | // when generating .pkg files.
|
---|
307 | deploymentList.append(CopyItem(Option::fixPathToLocalOS(info.absoluteFilePath()),
|
---|
308 | fixPathToEpocOS(devicePath + "/" + info.fileName()),
|
---|
309 | flags));
|
---|
310 | continue;
|
---|
311 | }
|
---|
312 | }
|
---|
313 | }
|
---|
314 |
|
---|
315 | int pathSize = info.absolutePath().size();
|
---|
316 | QDirIterator iterator(searchPath, QStringList() << nameFilter
|
---|
317 | , QDir::Files | QDir::NoDotAndDotDot | QDir::NoSymLinks
|
---|
318 | , dirSearch ? QDirIterator::Subdirectories : QDirIterator::NoIteratorFlags);
|
---|
319 |
|
---|
320 | while (iterator.hasNext()) {
|
---|
321 | iterator.next();
|
---|
322 | QFileInfo iteratorInfo(iterator.filePath());
|
---|
323 | QString absoluteItemPath = Option::fixPathToLocalOS(iteratorInfo.absolutePath());
|
---|
324 | int diffSize = absoluteItemPath.size() - pathSize;
|
---|
325 |
|
---|
326 | if (!iteratorInfo.isDir()) {
|
---|
327 | if (isPlugin(iterator.fileInfo(), devicePath)) {
|
---|
328 | // This deploys pre-built plugins. Other pre-built binaries will deploy normally,
|
---|
329 | // as they have SYSBIN_DIR target path.
|
---|
330 | if (deployBinaries
|
---|
331 | || (0 == platform.compare(QLatin1String(ROM_DEPLOYMENT_PLATFORM)))) {
|
---|
332 | if (devicePathHasDriveLetter) {
|
---|
333 | deploymentList.append(CopyItem(
|
---|
334 | Option::fixPathToLocalOS(absoluteItemPath + "/" + iterator.fileName()),
|
---|
335 | fixPathToEpocOS(devicePath.left(2) + QLatin1String(SYSBIN_DIR "/")
|
---|
336 | + iterator.fileName()),
|
---|
337 | flags));
|
---|
338 | } else {
|
---|
339 | deploymentList.append(CopyItem(
|
---|
340 | Option::fixPathToLocalOS(absoluteItemPath + "/" + iterator.fileName()),
|
---|
341 | fixPathToEpocOS(deploymentDrive + QLatin1String("/" SYSBIN_DIR "/")
|
---|
342 | + iterator.fileName()),
|
---|
343 | flags));
|
---|
344 | }
|
---|
345 | }
|
---|
346 | createPluginStub(info, devicePath + "/" + absoluteItemPath.right(diffSize),
|
---|
347 | deploymentList, generatedDirs, generatedFiles);
|
---|
348 | continue;
|
---|
349 | } else {
|
---|
350 | deploymentList.append(CopyItem(
|
---|
351 | Option::fixPathToLocalOS(absoluteItemPath + "/" + iterator.fileName()),
|
---|
352 | fixPathToEpocOS(devicePath + "/" + absoluteItemPath.right(diffSize)
|
---|
353 | + "/" + iterator.fileName()),
|
---|
354 | flags));
|
---|
355 | }
|
---|
356 | }
|
---|
357 | }
|
---|
358 | }
|
---|
359 | }
|
---|
360 |
|
---|
361 | // Remove deployments that do not actually do anything
|
---|
362 | if (0 == platform.compare(QLatin1String(EMULATOR_DEPLOYMENT_PLATFORM))
|
---|
363 | || 0 == platform.compare(QLatin1String(ROM_DEPLOYMENT_PLATFORM))) {
|
---|
364 | QMutableListIterator<CopyItem> i(deploymentList);
|
---|
365 | while(i.hasNext()) {
|
---|
366 | CopyItem &item = i.next();
|
---|
367 | QFileInfo fromItem(item.from);
|
---|
368 | QFileInfo toItem(item.to);
|
---|
369 | #if defined(Q_OS_WIN)
|
---|
370 | if (0 == fromItem.absoluteFilePath().compare(toItem.absoluteFilePath(), Qt::CaseInsensitive))
|
---|
371 | #else
|
---|
372 | if (0 == fromItem.absoluteFilePath().compare(toItem.absoluteFilePath()))
|
---|
373 | #endif
|
---|
374 | i.remove();
|
---|
375 | }
|
---|
376 | }
|
---|
377 | }
|
---|