|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2009 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 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
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 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
38 ** $QT_END_LICENSE$ |
|
39 ** |
|
40 ****************************************************************************/ |
|
41 |
|
42 #include "metamakefile.h" |
|
43 #include "qregexp.h" |
|
44 #include "qdir.h" |
|
45 #include "qdebug.h" |
|
46 #include "makefile.h" |
|
47 #include "project.h" |
|
48 #include "cachekeys.h" |
|
49 |
|
50 #define BUILDSMETATYPE 1 |
|
51 #define SUBDIRSMETATYPE 2 |
|
52 |
|
53 QT_BEGIN_NAMESPACE |
|
54 |
|
55 MetaMakefileGenerator::~MetaMakefileGenerator() |
|
56 { |
|
57 if(own_project) |
|
58 delete project; |
|
59 } |
|
60 |
|
61 class BuildsMetaMakefileGenerator : public MetaMakefileGenerator |
|
62 { |
|
63 private: |
|
64 bool init_flag; |
|
65 struct Build { |
|
66 QString name, build; |
|
67 MakefileGenerator *makefile; |
|
68 }; |
|
69 QList<Build *> makefiles; |
|
70 void clearBuilds(); |
|
71 MakefileGenerator *processBuild(const QString &); |
|
72 |
|
73 public: |
|
74 |
|
75 BuildsMetaMakefileGenerator(QMakeProject *p, const QString &n, bool op) : MetaMakefileGenerator(p, n, op), init_flag(false) { } |
|
76 virtual ~BuildsMetaMakefileGenerator() { clearBuilds(); } |
|
77 |
|
78 virtual bool init(); |
|
79 virtual int type() const { return BUILDSMETATYPE; } |
|
80 virtual bool write(const QString &); |
|
81 }; |
|
82 |
|
83 void |
|
84 BuildsMetaMakefileGenerator::clearBuilds() |
|
85 { |
|
86 for(int i = 0; i < makefiles.count(); i++) { |
|
87 Build *build = makefiles[i]; |
|
88 if(QMakeProject *p = build->makefile->projectFile()) { |
|
89 if(p != project) |
|
90 delete p; |
|
91 } |
|
92 delete build->makefile; |
|
93 delete build; |
|
94 } |
|
95 makefiles.clear(); |
|
96 } |
|
97 |
|
98 bool |
|
99 BuildsMetaMakefileGenerator::init() |
|
100 { |
|
101 if(init_flag) |
|
102 return false; |
|
103 init_flag = true; |
|
104 |
|
105 const QStringList &builds = project->variables()["BUILDS"]; |
|
106 bool use_single_build = builds.isEmpty(); |
|
107 if(builds.count() > 1 && Option::output.fileName() == "-") { |
|
108 use_single_build = true; |
|
109 warn_msg(WarnLogic, "Cannot direct to stdout when using multiple BUILDS."); |
|
110 } else if(0 && !use_single_build && project->first("TEMPLATE") == "subdirs") { |
|
111 use_single_build = true; |
|
112 warn_msg(WarnLogic, "Cannot specify multiple builds with TEMPLATE subdirs."); |
|
113 } |
|
114 if(!use_single_build) { |
|
115 for(int i = 0; i < builds.count(); i++) { |
|
116 QString build = builds[i]; |
|
117 MakefileGenerator *makefile = processBuild(build); |
|
118 if(!makefile) |
|
119 return false; |
|
120 if(!makefile->supportsMetaBuild()) { |
|
121 warn_msg(WarnLogic, "QMAKESPEC does not support multiple BUILDS."); |
|
122 clearBuilds(); |
|
123 use_single_build = true; |
|
124 break; |
|
125 } else { |
|
126 Build *b = new Build; |
|
127 b->name = name; |
|
128 if(builds.count() != 1) |
|
129 b->build += build; |
|
130 b->makefile = makefile; |
|
131 makefiles += b; |
|
132 } |
|
133 } |
|
134 } |
|
135 if(use_single_build) { |
|
136 Build *build = new Build; |
|
137 build->name = name; |
|
138 build->makefile = createMakefileGenerator(project, false); |
|
139 if (build->makefile){ |
|
140 makefiles += build; |
|
141 }else { |
|
142 delete build; |
|
143 return false; |
|
144 } |
|
145 } |
|
146 return true; |
|
147 } |
|
148 |
|
149 bool |
|
150 BuildsMetaMakefileGenerator::write(const QString &oldpwd) |
|
151 { |
|
152 Build *glue = 0; |
|
153 if(!makefiles.isEmpty() && !makefiles.first()->build.isNull()) { |
|
154 glue = new Build; |
|
155 glue->name = name; |
|
156 glue->makefile = createMakefileGenerator(project, true); |
|
157 makefiles += glue; |
|
158 } |
|
159 |
|
160 bool ret = true; |
|
161 const QString &output_name = Option::output.fileName(); |
|
162 for(int i = 0; ret && i < makefiles.count(); i++) { |
|
163 Option::output.setFileName(output_name); |
|
164 Build *build = makefiles[i]; |
|
165 |
|
166 bool using_stdout = false; |
|
167 if(build->makefile && (Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE || |
|
168 Option::qmake_mode == Option::QMAKE_GENERATE_PROJECT) |
|
169 && (!build->makefile->supportsMergedBuilds() |
|
170 || (build->makefile->supportsMergedBuilds() && (!glue || build == glue)))) { |
|
171 //open output |
|
172 if(!(Option::output.isOpen())) { |
|
173 if(Option::output.fileName() == "-") { |
|
174 Option::output.setFileName(""); |
|
175 Option::output_dir = qmake_getpwd(); |
|
176 Option::output.open(stdout, QIODevice::WriteOnly | QIODevice::Text); |
|
177 using_stdout = true; |
|
178 } else { |
|
179 if(Option::output.fileName().isEmpty() && |
|
180 Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE) |
|
181 Option::output.setFileName(project->first("QMAKE_MAKEFILE")); |
|
182 Option::output_dir = oldpwd; |
|
183 QString build_name = build->name; |
|
184 if(!build->build.isEmpty()) { |
|
185 if(!build_name.isEmpty()) |
|
186 build_name += "."; |
|
187 build_name += build->build; |
|
188 } |
|
189 if(!build->makefile->openOutput(Option::output, build_name)) { |
|
190 fprintf(stderr, "Failure to open file: %s\n", |
|
191 Option::output.fileName().isEmpty() ? "(stdout)" : |
|
192 Option::output.fileName().toLatin1().constData()); |
|
193 return false; |
|
194 } |
|
195 } |
|
196 } |
|
197 } else { |
|
198 using_stdout = true; //kind of.. |
|
199 } |
|
200 |
|
201 if(!build->makefile) { |
|
202 ret = false; |
|
203 } else if(build == glue) { |
|
204 ret = build->makefile->writeProjectMakefile(); |
|
205 } else { |
|
206 ret = build->makefile->write(); |
|
207 if (glue && glue->makefile->supportsMergedBuilds()) |
|
208 ret = glue->makefile->mergeBuildProject(build->makefile); |
|
209 } |
|
210 if(!using_stdout) { |
|
211 Option::output.close(); |
|
212 if(!ret) |
|
213 Option::output.remove(); |
|
214 } |
|
215 |
|
216 // debugging |
|
217 if(Option::debug_level) { |
|
218 QMap<QString, QStringList> &vars = project->variables(); |
|
219 for(QMap<QString, QStringList>::Iterator it = vars.begin(); it != vars.end(); ++it) { |
|
220 if(!it.key().startsWith(".") && !it.value().isEmpty()) |
|
221 debug_msg(1, "%s === %s", it.key().toLatin1().constData(), |
|
222 it.value().join(" :: ").toLatin1().constData()); |
|
223 } |
|
224 } |
|
225 } |
|
226 return ret; |
|
227 } |
|
228 |
|
229 MakefileGenerator |
|
230 *BuildsMetaMakefileGenerator::processBuild(const QString &build) |
|
231 { |
|
232 if(project) { |
|
233 debug_msg(1, "Meta Generator: Parsing '%s' for build [%s].", |
|
234 project->projectFile().toLatin1().constData(),build.toLatin1().constData()); |
|
235 |
|
236 //initialize the base |
|
237 QMap<QString, QStringList> basevars; |
|
238 if(!project->isEmpty(build + ".CONFIG")) |
|
239 basevars["CONFIG"] += project->values(build + ".CONFIG"); |
|
240 basevars["CONFIG"] += build; |
|
241 basevars["CONFIG"] += "build_pass"; |
|
242 basevars["BUILD_PASS"] = QStringList(build); |
|
243 QStringList buildname = project->values(build + ".name"); |
|
244 basevars["BUILD_NAME"] = (buildname.isEmpty() ? QStringList(build) : buildname); |
|
245 |
|
246 //create project |
|
247 QMakeProject *build_proj = new QMakeProject(project->properties(), basevars); |
|
248 |
|
249 //all the user configs must be set again afterwards (for .pro tests and for .prf tests) |
|
250 const QStringList old_after_user_config = Option::after_user_configs; |
|
251 const QStringList old_user_config = Option::user_configs; |
|
252 Option::after_user_configs += basevars["CONFIG"]; |
|
253 Option::user_configs += basevars["CONFIG"]; |
|
254 build_proj->read(project->projectFile()); |
|
255 Option::after_user_configs = old_after_user_config; |
|
256 Option::user_configs = old_user_config; |
|
257 |
|
258 //done |
|
259 return createMakefileGenerator(build_proj); |
|
260 } |
|
261 return 0; |
|
262 } |
|
263 |
|
264 class SubdirsMetaMakefileGenerator : public MetaMakefileGenerator |
|
265 { |
|
266 protected: |
|
267 bool init_flag; |
|
268 struct Subdir { |
|
269 Subdir() : makefile(0), indent(0) { } |
|
270 ~Subdir() { delete makefile; } |
|
271 QString input_dir; |
|
272 QString output_dir, output_file; |
|
273 MetaMakefileGenerator *makefile; |
|
274 int indent; |
|
275 }; |
|
276 QList<Subdir *> subs; |
|
277 MakefileGenerator *processBuild(const QString &); |
|
278 |
|
279 public: |
|
280 SubdirsMetaMakefileGenerator(QMakeProject *p, const QString &n, bool op) : MetaMakefileGenerator(p, n, op), init_flag(false) { } |
|
281 virtual ~SubdirsMetaMakefileGenerator(); |
|
282 |
|
283 virtual bool init(); |
|
284 virtual int type() const { return SUBDIRSMETATYPE; } |
|
285 virtual bool write(const QString &); |
|
286 }; |
|
287 |
|
288 bool |
|
289 SubdirsMetaMakefileGenerator::init() |
|
290 { |
|
291 if(init_flag) |
|
292 return false; |
|
293 init_flag = true; |
|
294 bool hasError = false; |
|
295 |
|
296 if(Option::recursive) { |
|
297 QString old_output_dir = Option::output_dir; |
|
298 QString old_output = Option::output.fileName(); |
|
299 QString oldpwd = qmake_getpwd(); |
|
300 QString thispwd = oldpwd; |
|
301 if(!thispwd.endsWith('/')) |
|
302 thispwd += '/'; |
|
303 const QStringList &subdirs = project->values("SUBDIRS"); |
|
304 static int recurseDepth = -1; |
|
305 ++recurseDepth; |
|
306 for(int i = 0; i < subdirs.size(); ++i) { |
|
307 Subdir *sub = new Subdir; |
|
308 sub->indent = recurseDepth; |
|
309 |
|
310 QFileInfo subdir(subdirs.at(i)); |
|
311 if(!project->isEmpty(subdirs.at(i) + ".file")) |
|
312 subdir = project->first(subdirs.at(i) + ".file"); |
|
313 else if(!project->isEmpty(subdirs.at(i) + ".subdir")) |
|
314 subdir = project->first(subdirs.at(i) + ".subdir"); |
|
315 QString sub_name; |
|
316 if(subdir.isDir()) |
|
317 subdir = QFileInfo(subdir.filePath() + "/" + subdir.fileName() + Option::pro_ext); |
|
318 else |
|
319 sub_name = subdir.baseName(); |
|
320 if(!subdir.isRelative()) { //we can try to make it relative |
|
321 QString subdir_path = subdir.filePath(); |
|
322 if(subdir_path.startsWith(thispwd)) |
|
323 subdir = QFileInfo(subdir_path.mid(thispwd.length())); |
|
324 } |
|
325 |
|
326 //handle sub project |
|
327 QMakeProject *sub_proj = new QMakeProject(project->properties()); |
|
328 if (!Option::mkfile::listgen) { |
|
329 for (int ind = 0; ind < sub->indent; ++ind) |
|
330 printf(" "); |
|
331 } |
|
332 |
|
333 sub->input_dir = subdir.absolutePath(); |
|
334 if(subdir.isRelative() && old_output_dir != oldpwd) { |
|
335 sub->output_dir = old_output_dir + "/" + subdir.path(); |
|
336 printf("Reading %s [%s]\n", subdir.absoluteFilePath().toLatin1().constData(), sub->output_dir.toLatin1().constData()); |
|
337 } else { //what about shadow builds? |
|
338 sub->output_dir = sub->input_dir; |
|
339 printf("Reading %s\n", subdir.absoluteFilePath().toLatin1().constData()); |
|
340 } |
|
341 qmake_setpwd(sub->input_dir); |
|
342 Option::output_dir = sub->output_dir; |
|
343 bool tmpError = !sub_proj->read(subdir.fileName()); |
|
344 if(!sub_proj->variables()["QMAKE_FAILED_REQUIREMENTS"].isEmpty()) { |
|
345 fprintf(stderr, "Project file(%s) not recursed because all requirements not met:\n\t%s\n", |
|
346 subdir.fileName().toLatin1().constData(), |
|
347 sub_proj->values("QMAKE_FAILED_REQUIREMENTS").join(" ").toLatin1().constData()); |
|
348 delete sub; |
|
349 delete sub_proj; |
|
350 Option::output_dir = old_output_dir; |
|
351 qmake_setpwd(oldpwd); |
|
352 continue; |
|
353 } else { |
|
354 hasError |= tmpError; |
|
355 } |
|
356 sub->makefile = MetaMakefileGenerator::createMetaGenerator(sub_proj, sub_name); |
|
357 if(0 && sub->makefile->type() == SUBDIRSMETATYPE) { |
|
358 subs.append(sub); |
|
359 } else { |
|
360 const QString output_name = Option::output.fileName(); |
|
361 Option::output.setFileName(sub->output_file); |
|
362 hasError |= !sub->makefile->write(sub->output_dir); |
|
363 delete sub; |
|
364 qmakeClearCaches(); |
|
365 sub = 0; |
|
366 Option::output.setFileName(output_name); |
|
367 } |
|
368 Option::output_dir = old_output_dir; |
|
369 qmake_setpwd(oldpwd); |
|
370 |
|
371 } |
|
372 --recurseDepth; |
|
373 Option::output.setFileName(old_output); |
|
374 Option::output_dir = old_output_dir; |
|
375 qmake_setpwd(oldpwd); |
|
376 } |
|
377 |
|
378 Subdir *self = new Subdir; |
|
379 self->input_dir = qmake_getpwd(); |
|
380 self->output_dir = Option::output_dir; |
|
381 if(!Option::recursive || (!Option::output.fileName().endsWith(Option::dir_sep) && !QFileInfo(Option::output).isDir())) |
|
382 self->output_file = Option::output.fileName(); |
|
383 self->makefile = new BuildsMetaMakefileGenerator(project, name, false); |
|
384 self->makefile->init(); |
|
385 subs.append(self); |
|
386 |
|
387 return !hasError; |
|
388 } |
|
389 |
|
390 bool |
|
391 SubdirsMetaMakefileGenerator::write(const QString &oldpwd) |
|
392 { |
|
393 bool ret = true; |
|
394 const QString &pwd = qmake_getpwd(); |
|
395 const QString &output_dir = Option::output_dir; |
|
396 const QString &output_name = Option::output.fileName(); |
|
397 for(int i = 0; ret && i < subs.count(); i++) { |
|
398 const Subdir *sub = subs.at(i); |
|
399 qmake_setpwd(subs.at(i)->input_dir); |
|
400 Option::output_dir = QFileInfo(subs.at(i)->output_dir).absoluteFilePath(); |
|
401 if(Option::output_dir.at(Option::output_dir.length()-1) != QLatin1Char('/')) |
|
402 Option::output_dir += QLatin1Char('/'); |
|
403 Option::output.setFileName(subs.at(i)->output_file); |
|
404 if(i != subs.count()-1) { |
|
405 if (!Option::mkfile::listgen) { |
|
406 for (int ind = 0; ind < sub->indent; ++ind) |
|
407 printf(" "); |
|
408 } |
|
409 printf("Writing %s\n", QDir::cleanPath(Option::output_dir+"/"+ |
|
410 Option::output.fileName()).toLatin1().constData()); |
|
411 } |
|
412 QString writepwd = Option::fixPathToLocalOS(qmake_getpwd()); |
|
413 if(!writepwd.startsWith(Option::fixPathToLocalOS(oldpwd))) |
|
414 writepwd = oldpwd; |
|
415 if(!(ret = subs.at(i)->makefile->write(writepwd))) |
|
416 break; |
|
417 //restore because I'm paranoid |
|
418 qmake_setpwd(pwd); |
|
419 Option::output.setFileName(output_name); |
|
420 Option::output_dir = output_dir; |
|
421 } |
|
422 return ret; |
|
423 } |
|
424 |
|
425 SubdirsMetaMakefileGenerator::~SubdirsMetaMakefileGenerator() |
|
426 { |
|
427 for(int i = 0; i < subs.count(); i++) |
|
428 delete subs[i]; |
|
429 subs.clear(); |
|
430 } |
|
431 |
|
432 class SymbianSubdirsMetaMakefileGenerator : public SubdirsMetaMakefileGenerator |
|
433 { |
|
434 public: |
|
435 SymbianSubdirsMetaMakefileGenerator(QMakeProject *p, const QString &n, bool op) : SubdirsMetaMakefileGenerator(p, n, op) { } |
|
436 virtual ~SymbianSubdirsMetaMakefileGenerator(); |
|
437 |
|
438 virtual bool init(); |
|
439 virtual bool write(const QString &); |
|
440 |
|
441 protected: |
|
442 |
|
443 static QMap<QString, QString> mmpPaths; |
|
444 |
|
445 static QMultiMap<QString, QString> mmpDependency; |
|
446 |
|
447 static QStringList getDependencyList(QString mmpFilename, int recursionDepth); |
|
448 |
|
449 static QStringList calculateRelativePaths(QString mmpParent, QStringList mmpChildren); |
|
450 |
|
451 private: |
|
452 QString cleanFromSpecialCharacters(QString& str); |
|
453 }; |
|
454 |
|
455 QMap<QString, QString> SymbianSubdirsMetaMakefileGenerator::mmpPaths; |
|
456 |
|
457 QMultiMap<QString, QString> SymbianSubdirsMetaMakefileGenerator::mmpDependency; |
|
458 |
|
459 QStringList SymbianSubdirsMetaMakefileGenerator::getDependencyList(QString mmpFilename, int recursionDepth) |
|
460 { |
|
461 QStringList list; |
|
462 |
|
463 QList<QString> values = mmpDependency.values(mmpFilename); |
|
464 if (recursionDepth < 0) { |
|
465 // special case; just first dependency level |
|
466 list = values; |
|
467 return list; |
|
468 } |
|
469 if (values.size() == 0) { |
|
470 //reached recursion END condition |
|
471 if (recursionDepth == 0) { |
|
472 --recursionDepth; |
|
473 return list; // empty list // no dependencies / return |
|
474 } else { |
|
475 list.append(mmpFilename); |
|
476 recursionDepth--; |
|
477 return list; // leaf // return |
|
478 } |
|
479 } else { |
|
480 recursionDepth++; |
|
481 for (int i = 0; i < values.size(); ++i) { |
|
482 QString current = values.at(i); |
|
483 QStringList tailList = getDependencyList(current, recursionDepth); |
|
484 for (int j = 0; j < tailList.size(); ++j) { |
|
485 QString path = tailList.at(j); |
|
486 list.append(path); |
|
487 } |
|
488 } |
|
489 |
|
490 if (recursionDepth > 0) { |
|
491 //for mmp somewhere in middle |
|
492 list.append(mmpFilename); |
|
493 } |
|
494 recursionDepth--; |
|
495 return list; |
|
496 } |
|
497 } |
|
498 |
|
499 SymbianSubdirsMetaMakefileGenerator::~SymbianSubdirsMetaMakefileGenerator() { } |
|
500 |
|
501 bool SymbianSubdirsMetaMakefileGenerator::write(const QString &oldpwd) |
|
502 { |
|
503 return SubdirsMetaMakefileGenerator::write(oldpwd); |
|
504 } |
|
505 |
|
506 QString SymbianSubdirsMetaMakefileGenerator::cleanFromSpecialCharacters(QString& str) |
|
507 { |
|
508 QString tmp = str; |
|
509 |
|
510 tmp.replace(QString("/"), QString("_")); |
|
511 tmp.replace(QString("\\"), QString("_")); |
|
512 tmp.replace(QString("-"), QString("_")); |
|
513 tmp.replace(QString(":"), QString("_")); |
|
514 tmp.replace(QString("."), QString("_")); |
|
515 |
|
516 return tmp; |
|
517 } |
|
518 |
|
519 bool SymbianSubdirsMetaMakefileGenerator::init() |
|
520 { |
|
521 if (init_flag) |
|
522 return false; |
|
523 |
|
524 init_flag = true; |
|
525 |
|
526 // If we are here then we have template == subdirs |
|
527 |
|
528 Option::recursive = true; |
|
529 |
|
530 if (Option::recursive) { |
|
531 QString old_output_dir = QDir::cleanPath(Option::output_dir); |
|
532 if (!old_output_dir.endsWith('/')) |
|
533 old_output_dir += '/'; |
|
534 QString old_output = Option::output.fileName(); |
|
535 QString oldpwd = QDir::cleanPath(qmake_getpwd()); |
|
536 |
|
537 if (!oldpwd.endsWith('/')) |
|
538 oldpwd += '/'; |
|
539 |
|
540 // find the parent mmp filename |
|
541 int end = oldpwd.size() - 1; |
|
542 int start = oldpwd.lastIndexOf("/", end - 2); |
|
543 QString parentMmpFilename = oldpwd.mid(start + 1, end - start - 1); |
|
544 parentMmpFilename.prepend(oldpwd); |
|
545 parentMmpFilename = parentMmpFilename.append(Option::mmp_ext); |
|
546 |
|
547 |
|
548 const QStringList &subdirs = project->values("SUBDIRS"); |
|
549 static int recurseDepth = -1; |
|
550 ++recurseDepth; |
|
551 for (int i = 0; i < subdirs.size(); ++i) { |
|
552 Subdir *sub = new Subdir; |
|
553 sub->indent = recurseDepth; |
|
554 |
|
555 QFileInfo subdir(subdirs.at(i)); |
|
556 // childMmpFielname should be derived from subdirName |
|
557 QString subdirName = subdirs.at(i); |
|
558 if (!project->isEmpty(subdirs.at(i) + ".file")) |
|
559 subdir = project->first(subdirs.at(i) + ".file"); |
|
560 else if (!project->isEmpty(subdirs.at(i) + ".subdir")) |
|
561 subdir = project->first(subdirs.at(i) + ".subdir"); |
|
562 QString sub_name; |
|
563 |
|
564 QString childMmpFilename; |
|
565 |
|
566 if (subdir.isDir()) { |
|
567 subdir = QFileInfo(subdir.filePath() + "/" + subdir.fileName() + Option::pro_ext); |
|
568 childMmpFilename = subdir.fileName(); |
|
569 childMmpFilename = subdir.absoluteFilePath(); |
|
570 childMmpFilename.replace(Option::pro_ext, QString("")); |
|
571 childMmpFilename.append(Option::mmp_ext); |
|
572 } else { |
|
573 childMmpFilename = subdir.absoluteFilePath(); |
|
574 childMmpFilename.replace(Option::pro_ext, Option::mmp_ext); |
|
575 sub_name = childMmpFilename; |
|
576 sub_name.replace(Option::mmp_ext, QString("")); |
|
577 sub_name.replace(0, sub_name.lastIndexOf("/") + 1, QString("")); |
|
578 project->values("SHADOW_BLD_INFS").append(QString("bld.inf.") + sub_name); |
|
579 } |
|
580 |
|
581 //handle sub project |
|
582 QMakeProject *sub_proj = new QMakeProject(project->properties()); |
|
583 |
|
584 if (!Option::mkfile::listgen) { |
|
585 for (int ind = 0; ind < sub->indent; ++ind) |
|
586 printf(" "); |
|
587 } |
|
588 |
|
589 sub->input_dir = subdir.absolutePath(); |
|
590 if (subdir.isRelative() && old_output_dir != oldpwd) { |
|
591 sub->output_dir = old_output_dir + "/" + subdir.path(); |
|
592 printf("Reading %s [%s]\n", subdir.absoluteFilePath().toLatin1().constData(), sub->output_dir.toLatin1().constData()); |
|
593 } else { |
|
594 sub->output_dir = sub->input_dir; |
|
595 printf("Reading %s\n", subdir.absoluteFilePath().toLatin1().constData()); |
|
596 } |
|
597 |
|
598 // find the child mmp filename |
|
599 qmake_setpwd(sub->input_dir); |
|
600 |
|
601 QString newpwd = qmake_getpwd(); |
|
602 |
|
603 Option::output_dir = sub->output_dir; |
|
604 if (Option::output_dir.at(Option::output_dir.length() - 1) != QLatin1Char('/')) |
|
605 Option::output_dir += QLatin1Char('/'); |
|
606 sub_proj->read(subdir.fileName()); |
|
607 if (!sub_proj->variables()["QMAKE_FAILED_REQUIREMENTS"].isEmpty()) { |
|
608 fprintf(stderr, "Project file(%s) not recursed because all requirements not met:\n\t%s\n", |
|
609 subdir.fileName().toLatin1().constData(), |
|
610 sub_proj->values("QMAKE_FAILED_REQUIREMENTS").join(" ").toLatin1().constData()); |
|
611 delete sub; |
|
612 delete sub_proj; |
|
613 //continue; |
|
614 } else { |
|
615 // map mmpfile to its absolut filepath |
|
616 mmpPaths.insert(childMmpFilename, newpwd); |
|
617 |
|
618 // update mmp files dependency map |
|
619 mmpDependency.insert(parentMmpFilename, childMmpFilename); |
|
620 |
|
621 sub->makefile = MetaMakefileGenerator::createMetaGenerator(sub_proj, sub_name); |
|
622 if (0 && sub->makefile->type() == SUBDIRSMETATYPE) { |
|
623 subs.append(sub); |
|
624 } else { |
|
625 const QString output_name = Option::output.fileName(); |
|
626 Option::output.setFileName(sub->output_file); |
|
627 sub->makefile->write(sub->output_dir); |
|
628 delete sub; |
|
629 qmakeClearCaches(); |
|
630 sub = 0; |
|
631 Option::output.setFileName(output_name); |
|
632 } |
|
633 } |
|
634 |
|
635 Option::output_dir = old_output_dir; |
|
636 qmake_setpwd(oldpwd); |
|
637 |
|
638 } |
|
639 --recurseDepth; |
|
640 Option::output.setFileName(old_output); |
|
641 Option::output_dir = old_output_dir; |
|
642 qmake_setpwd(oldpwd); |
|
643 } |
|
644 |
|
645 Subdir *self = new Subdir; |
|
646 self->input_dir = qmake_getpwd(); |
|
647 |
|
648 // To fully expand find all dependencies: |
|
649 // Do as recursion, then insert result as subdirs data in project |
|
650 QString newpwd = qmake_getpwd(); |
|
651 if (!newpwd.endsWith('/')) |
|
652 newpwd += '/'; |
|
653 int end = newpwd.size() - 1; |
|
654 int start = newpwd.lastIndexOf("/", end - 2); |
|
655 QString mmpFilename = newpwd.mid(start + 1, end - start - 1); |
|
656 mmpFilename.prepend(newpwd); |
|
657 mmpFilename = mmpFilename.append(Option::mmp_ext); |
|
658 |
|
659 // map mmpfile to its absolute filepath |
|
660 mmpPaths.insert(mmpFilename, newpwd); |
|
661 |
|
662 QStringList directDependencyList = getDependencyList(mmpFilename, -1); |
|
663 for (int i = 0; i < directDependencyList.size(); ++i) { |
|
664 project->values("MMPFILES_DIRECT_DEPENDS").append(directDependencyList.at(i)); |
|
665 } |
|
666 |
|
667 QStringList dependencyList = getDependencyList(mmpFilename, 0); |
|
668 |
|
669 self->output_dir = Option::output_dir; |
|
670 if (!Option::recursive || (!Option::output.fileName().endsWith(Option::dir_sep) && !QFileInfo(Option::output).isDir())) |
|
671 self->output_file = Option::output.fileName(); |
|
672 self->makefile = new BuildsMetaMakefileGenerator(project, name, false); |
|
673 self->makefile->init(); |
|
674 subs.append(self); |
|
675 |
|
676 return true; |
|
677 } |
|
678 |
|
679 QStringList SymbianSubdirsMetaMakefileGenerator::calculateRelativePaths(QString mmpParent, QStringList mmpChildren) |
|
680 { |
|
681 QStringList mmpRelativePaths; |
|
682 QString parentDir = mmpPaths.value(mmpParent); |
|
683 QDir directory(parentDir); |
|
684 for (int i = 0; i < mmpChildren.size(); ++i) { |
|
685 QString childDir = mmpPaths.value(mmpChildren.at(i)); |
|
686 if (mmpChildren.at(i) == mmpParent) |
|
687 mmpRelativePaths.append(mmpChildren.at(i)); |
|
688 else { |
|
689 QString relativePath = directory.relativeFilePath(childDir); |
|
690 if (relativePath.startsWith("..")) |
|
691 mmpRelativePaths.append(childDir); |
|
692 else |
|
693 directory.relativeFilePath(relativePath); |
|
694 } |
|
695 } |
|
696 return mmpRelativePaths; |
|
697 } |
|
698 |
|
699 //Factory things |
|
700 QT_BEGIN_INCLUDE_NAMESPACE |
|
701 #include "unixmake.h" |
|
702 #include "mingw_make.h" |
|
703 #include "projectgenerator.h" |
|
704 #include "pbuilder_pbx.h" |
|
705 #include "msvc_nmake.h" |
|
706 #include "borland_bmake.h" |
|
707 #include "msvc_dsp.h" |
|
708 #include "msvc_vcproj.h" |
|
709 #include "symmake_abld.h" |
|
710 #include "symmake_sbsv2.h" |
|
711 QT_END_INCLUDE_NAMESPACE |
|
712 |
|
713 MakefileGenerator * |
|
714 MetaMakefileGenerator::createMakefileGenerator(QMakeProject *proj, bool noIO) |
|
715 { |
|
716 MakefileGenerator *mkfile = NULL; |
|
717 if(Option::qmake_mode == Option::QMAKE_GENERATE_PROJECT) { |
|
718 mkfile = new ProjectGenerator; |
|
719 mkfile->setProjectFile(proj); |
|
720 return mkfile; |
|
721 } |
|
722 |
|
723 QString gen = proj->first("MAKEFILE_GENERATOR"); |
|
724 if(gen.isEmpty()) { |
|
725 fprintf(stderr, "MAKEFILE_GENERATOR variable not set as a result of parsing : %s. Possibly qmake was not able to find files included using \"include(..)\" - enable qmake debugging to investigate more.\n", |
|
726 proj->projectFile().toLatin1().constData()); |
|
727 } else if(gen == "UNIX") { |
|
728 mkfile = new UnixMakefileGenerator; |
|
729 } else if(gen == "MINGW") { |
|
730 mkfile = new MingwMakefileGenerator; |
|
731 } else if(gen == "PROJECTBUILDER" || gen == "XCODE") { |
|
732 mkfile = new ProjectBuilderMakefileGenerator; |
|
733 } else if(gen == "MSVC") { |
|
734 // Visual Studio =< v6.0 |
|
735 if(proj->first("TEMPLATE").indexOf(QRegExp("^vc.*")) != -1) |
|
736 mkfile = new DspMakefileGenerator; |
|
737 else |
|
738 mkfile = new NmakeMakefileGenerator; |
|
739 } else if(gen == "MSVC.NET") { |
|
740 // Visual Studio >= v7.0 |
|
741 if(proj->first("TEMPLATE").indexOf(QRegExp("^vc.*")) != -1 || proj->first("TEMPLATE").indexOf(QRegExp("^ce.*")) != -1) |
|
742 mkfile = new VcprojGenerator; |
|
743 else |
|
744 mkfile = new NmakeMakefileGenerator; |
|
745 } else if(gen == "BMAKE") { |
|
746 mkfile = new BorlandMakefileGenerator; |
|
747 } else if(gen == "SYMBIAN_ABLD") { |
|
748 mkfile = new SymbianAbldMakefileGenerator; |
|
749 } else if(gen == "SYMBIAN_SBSV2") { |
|
750 mkfile = new SymbianSbsv2MakefileGenerator; |
|
751 } else { |
|
752 fprintf(stderr, "Unknown generator specified: %s\n", gen.toLatin1().constData()); |
|
753 } |
|
754 if (mkfile) { |
|
755 mkfile->setNoIO(noIO); |
|
756 mkfile->setProjectFile(proj); |
|
757 } |
|
758 return mkfile; |
|
759 } |
|
760 |
|
761 MetaMakefileGenerator * |
|
762 MetaMakefileGenerator::createMetaGenerator(QMakeProject *proj, const QString &name, bool op, bool *success) |
|
763 { |
|
764 MetaMakefileGenerator *ret = 0; |
|
765 if ((Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE || |
|
766 Option::qmake_mode == Option::QMAKE_GENERATE_PRL)) { |
|
767 if (proj->first("TEMPLATE").endsWith("subdirs")) |
|
768 ret = new SubdirsMetaMakefileGenerator(proj, name, op); |
|
769 } |
|
770 if (!ret) |
|
771 ret = new BuildsMetaMakefileGenerator(proj, name, op); |
|
772 bool res = ret->init(); |
|
773 if (success) |
|
774 *success = res; |
|
775 return ret; |
|
776 } |
|
777 |
|
778 QT_END_NAMESPACE |