source: trunk/qmake/generators/makefile.cpp@ 7

Last change on this file since 7 was 2, checked in by dmik, 20 years ago

Imported xplatform parts of the official release 3.3.1 from Trolltech

  • Property svn:keywords set to Id
File size: 87.6 KB
Line 
1/****************************************************************************
2** $Id: makefile.cpp 2 2005-11-16 15:49:26Z dmik $
3**
4** Implementation of MakefileGenerator class.
5**
6** Copyright (C) 1992-2003 Trolltech AS. All rights reserved.
7**
8** This file is part of qmake.
9**
10** This file may be distributed under the terms of the Q Public License
11** as defined by Trolltech AS of Norway and appearing in the file
12** LICENSE.QPL included in the packaging of this file.
13**
14** This file may be distributed and/or modified under the terms of the
15** GNU General Public License version 2 as published by the Free Software
16** Foundation and appearing in the file LICENSE.GPL included in the
17** packaging of this file.
18**
19** Licensees holding valid Qt Enterprise Edition licenses may use this
20** file in accordance with the Qt Commercial License Agreement provided
21** with the Software.
22**
23** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
24** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
25**
26** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
27** information about Qt Commercial License Agreements.
28** See http://www.trolltech.com/qpl/ for QPL licensing information.
29** See http://www.trolltech.com/gpl/ for GPL licensing information.
30**
31** Contact info@trolltech.com if any conditions of this licensing are
32** not clear to you.
33**
34**********************************************************************/
35
36#include "makefile.h"
37#include "option.h"
38#include "meta.h"
39#include <qdir.h>
40#include <qfile.h>
41#include <qtextstream.h>
42#include <qregexp.h>
43#include <qdict.h>
44#if defined(Q_OS_UNIX)
45#include <unistd.h>
46#else
47#include <io.h>
48#endif
49#include <stdio.h>
50#include <stdlib.h>
51#include <time.h>
52#include <fcntl.h>
53#include <sys/types.h>
54#include <sys/stat.h>
55
56// Well, Windows doesn't have this, so here's the macro
57#ifndef S_ISDIR
58#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
59#endif
60
61QString mkdir_p_asstring(const QString &dir)
62{
63 QString ret = "@$(CHK_DIR_EXISTS) \"" + dir + "\" ";
64 if(Option::target_mode == Option::TARG_WIN_MODE)
65 ret += "$(MKDIR)";
66 else
67 ret += "|| $(MKDIR)";
68 ret += " \"" + dir + "\"";
69 return ret;
70}
71
72static bool createDir(const QString& fullPath)
73{
74 if(QFile::exists(fullPath))
75 return FALSE;
76 QDir dirTmp;
77 bool ret = TRUE;
78 QString pathComponent, tmpPath;
79 QStringList hierarchy = QStringList::split(QString(Option::dir_sep), fullPath, TRUE);
80 for(QStringList::Iterator it = hierarchy.begin(); it != hierarchy.end(); ++it) {
81 pathComponent = *it + QDir::separator();
82 tmpPath += pathComponent;
83 if(!dirTmp.mkdir(tmpPath)) {
84 ret = FALSE;
85// break;
86 }
87 }
88 return ret;
89}
90
91
92MakefileGenerator::MakefileGenerator(QMakeProject *p) : init_opath_already(FALSE),
93 init_already(FALSE), moc_aware(FALSE),
94 no_io(FALSE), project(p)
95{
96}
97
98static char *gimme_buffer(off_t s)
99{
100 static char *big_buffer = NULL;
101 static int big_buffer_size = 0;
102 if(!big_buffer || big_buffer_size < s)
103 big_buffer = (char *)realloc(big_buffer, s);
104 return big_buffer;
105}
106
107bool
108MakefileGenerator::generateMocList(const QString &fn_target)
109{
110 if(!findMocDestination(fn_target).isEmpty())
111 return TRUE;
112
113 QString fn_local = Option::fixPathToLocalOS(fileFixify(fn_target, QDir::currentDirPath(), Option::output_dir));
114
115 int file = open(fn_local.latin1(), O_RDONLY);
116 if(file == -1)
117 return FALSE;
118
119 struct stat fst;
120 if(fstat(file, &fst) || S_ISDIR(fst.st_mode))
121 return FALSE; //shouldn't happen
122 char *big_buffer = gimme_buffer(fst.st_size);
123
124 int total_size_read;
125 for(int have_read = total_size_read = 0;
126 (have_read = read(file, big_buffer + total_size_read,
127 fst.st_size - total_size_read));
128 total_size_read += have_read);
129 close(file);
130
131 bool ignore_qobject = FALSE;
132 int line_count = 1;
133 /* qmake ignore Q_OBJECT */
134#define COMP_LEN 8 //strlen("Q_OBJECT")
135#define OBJ_LEN 8 //strlen("Q_OBJECT")
136#define DIS_LEN 10 //strlen("Q_DISPATCH")
137 int x;
138 for(x = 0; x < (total_size_read-COMP_LEN); x++) {
139 if(*(big_buffer + x) == '/') {
140 x++;
141 if(total_size_read >= x) {
142 if(*(big_buffer + x) == '/') { //c++ style comment
143 for( ;x < total_size_read && *(big_buffer + x) != '\n'; x++);
144 line_count++;
145 } else if(*(big_buffer + x) == '*') { //c style comment
146 for( ;x < total_size_read; x++) {
147 if(*(big_buffer + x) == 't' || *(big_buffer + x) == 'q') { //ignore
148 if(total_size_read >= (x + 20)) {
149 if(!strncmp(big_buffer + x + 1, "make ignore Q_OBJECT", 20)) {
150 debug_msg(2, "Mocgen: %s:%d Found \"qmake ignore Q_OBJECT\"",
151 fn_target.latin1(), line_count);
152 x += 20;
153 ignore_qobject = TRUE;
154 }
155 }
156 } else if(*(big_buffer + x) == '*') {
157 if(total_size_read >= (x+1) && *(big_buffer + (x+1)) == '/') {
158 x += 2;
159 break;
160 }
161 } else if(*(big_buffer + x) == '\n') {
162 line_count++;
163 }
164 }
165 }
166 }
167 }
168#define SYMBOL_CHAR(x) ((x >= 'a' && x <= 'z') || (x >= 'A' && x <= 'Z') || \
169 (x <= '0' && x >= '9') || x == '_')
170
171 bool interesting = *(big_buffer+x) == 'Q' && (!strncmp(big_buffer+x, "Q_OBJECT", OBJ_LEN) ||
172 !strncmp(big_buffer+x, "Q_DISPATCH", DIS_LEN));
173 if(interesting) {
174 int len = 0;
175 if(!strncmp(big_buffer+x, "Q_OBJECT", OBJ_LEN)) {
176 if(ignore_qobject) {
177 debug_msg(2, "Mocgen: %s:%d Ignoring Q_OBJECT", fn_target.latin1(), line_count);
178 interesting = FALSE;
179 }
180 len=OBJ_LEN;
181 } else if(!strncmp(big_buffer+x, "Q_DISPATCH", DIS_LEN)) {
182 len=DIS_LEN;
183 }
184 if(SYMBOL_CHAR(*(big_buffer+x+len)))
185 interesting = FALSE;
186 if(interesting) {
187 *(big_buffer+x+len) = '\0';
188 debug_msg(2, "Mocgen: %s:%d Found MOC symbol %s", fn_target.latin1(),
189 line_count, big_buffer+x);
190
191 int ext_pos = fn_target.findRev('.');
192 int ext_len = fn_target.length() - ext_pos;
193 int dir_pos = fn_target.findRev(Option::dir_sep, ext_pos);
194 QString mocFile;
195 if(!project->isEmpty("MOC_DIR"))
196 mocFile = project->first("MOC_DIR");
197 else if(dir_pos != -1)
198 mocFile = fn_target.left(dir_pos+1);
199
200 bool cpp_ext = FALSE;
201 for(QStringList::Iterator cppit = Option::cpp_ext.begin();
202 cppit != Option::cpp_ext.end(); ++cppit) {
203 if((cpp_ext = (fn_target.right(ext_len) == (*cppit))))
204 break;
205 }
206 if(cpp_ext) {
207 mocFile += Option::cpp_moc_mod + fn_target.mid(dir_pos+1, ext_pos - dir_pos-1) + Option::cpp_moc_ext;
208 project->variables()["_SRCMOC"].append(mocFile);
209 } else if(project->variables()["HEADERS"].findIndex(fn_target) != -1) {
210 for(QStringList::Iterator hit = Option::h_ext.begin();
211 hit != Option::h_ext.end(); ++hit) {
212 if((fn_target.right(ext_len) == (*hit))) {
213 mocFile += Option::h_moc_mod + fn_target.mid(dir_pos+1, ext_pos - dir_pos-1) +
214 Option::h_moc_ext;
215 logicWarn(mocFile, "SOURCES");
216 project->variables()["_HDRMOC"].append(mocFile);
217 break;
218 }
219 }
220 }
221
222 if(!mocFile.isEmpty()) {
223 mocFile = Option::fixPathToTargetOS(mocFile);
224 mocablesToMOC[cleanFilePath(fn_target)] = mocFile;
225 mocablesFromMOC[cleanFilePath(mocFile)] = fn_target;
226 }
227 break;
228 }
229 }
230
231 while(x < total_size_read && SYMBOL_CHAR(*(big_buffer+x)))
232 x++;
233 if(*(big_buffer+x) == '\n')
234 line_count++;
235 }
236#undef OBJ_LEN
237#undef DIS_LEN
238 return TRUE;
239}
240
241bool
242MakefileGenerator::generateDependencies(QPtrList<MakefileDependDir> &dirs, const QString &f, bool recurse)
243{
244 if(processedDependencies(f))
245 return TRUE;
246 setProcessedDependencies(f, TRUE);
247
248 QStringList &fndeps = findDependencies(f);
249 QString fn = fileFixify(f, QDir::currentDirPath(), Option::output_dir);
250 fn = Option::fixPathToLocalOS(fn, FALSE);
251 QString fix_env_fn = Option::fixPathToLocalOS(fn);
252 int file = open(fix_env_fn.latin1(), O_RDONLY);
253 if(file == -1)
254 return FALSE;
255 struct stat fst;
256 if(fstat(file, &fst) || S_ISDIR(fst.st_mode))
257 return FALSE; //shouldn't happen
258
259 QString fndir, fix_env_fndir;
260 int dl = fn.findRev(Option::dir_sep);
261 if(dl != -1)
262 fndir = fn.left(dl+1);
263 dl = fix_env_fn.findRev(Option::dir_sep);
264 if(dl != -1)
265 fix_env_fndir = fix_env_fn.left(dl + 1);
266
267 int line_count = 1;
268 char *big_buffer = gimme_buffer(fst.st_size);
269
270 int total_size_read;
271 for(int have_read = total_size_read = 0;
272 (have_read = read(file, big_buffer + total_size_read,
273 fst.st_size - total_size_read));
274 total_size_read += have_read);
275 close(file);
276
277 bool ui_file = fn.endsWith(Option::ui_ext);
278 for(int x = 0; x < total_size_read; x++) {
279 QStringList *outdeps=&fndeps;
280 QString inc;
281 if(!ui_file) {
282 if(*(big_buffer + x) == '/') {
283 x++;
284 if(total_size_read >= x) {
285 if(*(big_buffer + x) == '/') { //c++ style comment
286 for( ; x < total_size_read && *(big_buffer + x) != '\n'; x++);
287 } else if(*(big_buffer + x) == '*') { //c style comment
288 for( ; x < total_size_read; x++) {
289 if(*(big_buffer + x) == '*') {
290 if(total_size_read >= (x+1) && *(big_buffer + (x+1)) == '/') {
291 x += 2;
292 break;
293 }
294 } else if(*(big_buffer + x) == '\n') {
295 line_count++;
296 }
297 }
298 }
299 }
300 }
301 if(*(big_buffer + x) == '#') {
302 x++;
303 while(x < total_size_read && //Skip spaces after hash
304 (*(big_buffer+x) == ' ' || *(big_buffer+x) == '\t'))
305 x++;
306 if(total_size_read >= x + 8 && !strncmp(big_buffer + x, "include", 7) &&
307 (*(big_buffer + x + 7) == ' ' || *(big_buffer + x + 7) == '\t' ||
308 *(big_buffer + x + 7) == '<' || *(big_buffer + x + 7) == '"')) {
309 for(x+=7; //skip spaces after keyword
310 x < total_size_read && (*(big_buffer+x) == ' ' || *(big_buffer+x) == '\t');
311 x++);
312 char term = *(big_buffer + x);
313 if(term == '"');
314 else if(term == '<')
315 term = '>';
316 else
317 continue; //wtf?
318 x++;
319
320 int inc_len;
321 for(inc_len = 0; *(big_buffer + x + inc_len) != term &&
322 *(big_buffer + x + inc_len) != '\n'; inc_len++);
323 *(big_buffer + x + inc_len) = '\0';
324 inc = big_buffer + x;
325 } else if(total_size_read >= x + 14 && !strncmp(big_buffer + x, "qmake_warning ", 14)) {
326 for(x+=14; //skip spaces after keyword
327 x < total_size_read && (*(big_buffer+x) == ' ' || *(big_buffer+x) == '\t');
328 x++);
329 char term = '\n';
330 if(*(big_buffer + x) == '"')
331 term = '"';
332 if(*(big_buffer + x) == '\'')
333 term = '\'';
334 if(term != '\n')
335 x++;
336
337 int msg_len;
338 for(msg_len = 0; *(big_buffer + x + msg_len) != term &&
339 *(big_buffer + x + msg_len) != '\n'; msg_len++);
340 *(big_buffer + x + msg_len) = '\0';
341 QString msg = big_buffer + x;
342 debug_msg(0, "%s:%d qmake_warning -- %s", fix_env_fn.latin1(),
343 line_count, msg.latin1());
344 *(big_buffer + x + msg_len) = term; //put it back
345 }
346 }
347 } else if(ui_file) {
348 // skip whitespaces
349 while(x < total_size_read &&
350 (*(big_buffer+x) == ' ' || *(big_buffer+x) == '\t'))
351 x++;
352 if(*(big_buffer + x) == '<') {
353 x++;
354 if(total_size_read >= x + 12 && !strncmp(big_buffer + x, "includehint", 11) &&
355 (*(big_buffer + x + 11) == ' ' || *(big_buffer + x + 11) == '>')) {
356 for(x += 12; *(big_buffer + x) != '>'; x++);
357 int inc_len = 0;
358 for(x += 1 ; *(big_buffer + x + inc_len) != '<'; inc_len++);
359 *(big_buffer + x + inc_len) = '\0';
360 inc = big_buffer + x;
361 } else if(total_size_read >= x + 13 && !strncmp(big_buffer + x, "customwidget", 12) &&
362 (*(big_buffer + x + 12) == ' ' || *(big_buffer + x + 12) == '>')) {
363 for(x += 13; *(big_buffer + x) != '>'; x++); //skip up to >
364 while(x < total_size_read) {
365 for(x++; *(big_buffer + x) != '<'; x++); //skip up to <
366 x++;
367 if(total_size_read >= x + 7 && !strncmp(big_buffer+x, "header", 6) &&
368 (*(big_buffer + x + 6) == ' ' || *(big_buffer + x + 6) == '>')) {
369 for(x += 7; *(big_buffer + x) != '>'; x++); //skip up to >
370 int inc_len = 0;
371 for(x += 1 ; *(big_buffer + x + inc_len) != '<'; inc_len++);
372 *(big_buffer + x + inc_len) = '\0';
373 inc = big_buffer + x;
374 break;
375 } else if(total_size_read >= x + 14 && !strncmp(big_buffer+x, "/customwidget", 13) &&
376 (*(big_buffer + x + 13) == ' ' || *(big_buffer + x + 13) == '>')) {
377 x += 14;
378 break;
379 }
380 }
381 } else if(total_size_read >= x + 8 && !strncmp(big_buffer + x, "include", 7) &&
382 (*(big_buffer + x + 7) == ' ' || *(big_buffer + x + 7) == '>')) {
383 for(x += 8; *(big_buffer + x) != '>'; x++) {
384 if(total_size_read >= x + 9 && *(big_buffer + x) == 'i' &&
385 !strncmp(big_buffer + x, "impldecl", 8)) {
386 for(x += 8; *(big_buffer + x) != '='; x++);
387 if(*(big_buffer + x) != '=')
388 continue;
389 for(x++; *(big_buffer+x) == '\t' || *(big_buffer+x) == ' '; x++);
390 char quote = 0;
391 if(*(big_buffer+x) == '\'' || *(big_buffer+x) == '"') {
392 quote = *(big_buffer + x);
393 x++;
394 }
395 int val_len;
396 for(val_len = 0; TRUE; val_len++) {
397 if(quote) {
398 if(*(big_buffer+x+val_len) == quote)
399 break;
400 } else if(*(big_buffer + x + val_len) == '>' ||
401 *(big_buffer + x + val_len) == ' ') {
402 break;
403 }
404 }
405 char saved = *(big_buffer + x + val_len);
406 *(big_buffer + x + val_len) = '\0';
407 QString where = big_buffer + x;
408 *(big_buffer + x + val_len) = saved;
409 if(where == "in implementation") {
410 QString cpp = fn.left(fn.length() - Option::ui_ext.length()) +
411 Option::cpp_ext.first();
412 outdeps = &findDependencies(cpp);
413 }
414 }
415 }
416 int inc_len = 0;
417 for(x += 1 ; *(big_buffer + x + inc_len) != '<'; inc_len++);
418 *(big_buffer + x + inc_len) = '\0';
419 inc = big_buffer + x;
420 }
421 }
422 }
423
424 if(!inc.isEmpty()) {
425 bool from_source_dir = TRUE;
426 debug_msg(5, "%s:%d Found dependency to %s", fix_env_fn.latin1(),
427 line_count, inc.latin1());
428 if(!project->isEmpty("SKIP_DEPENDS")) {
429 bool found = FALSE;
430 QStringList &nodeplist = project->values("SKIP_DEPENDS");
431 for(QStringList::Iterator it = nodeplist.begin();
432 it != nodeplist.end(); ++it) {
433 QRegExp regx((*it));
434 if(regx.search(inc) != -1) {
435 found = TRUE;
436 break;
437 }
438 }
439 if(found)
440 continue;
441 }
442 QString fqn;
443 if(project->isEmpty("QMAKE_ABSOLUTE_SOURCE_PATH") &&
444 !stat(fix_env_fndir + inc, &fst) && !S_ISDIR(fst.st_mode)) {
445 fqn = fndir + inc;
446 goto handle_fqn;
447 } else {
448 if((Option::target_mode == Option::TARG_MAC9_MODE && inc.find(':')) ||
449 (Option::target_mode == Option::TARG_WIN_MODE && inc[1] != ':') ||
450 ((Option::target_mode == Option::TARG_UNIX_MODE ||
451 Option::target_mode == Option::TARG_QNX6_MODE ||
452 Option::target_mode == Option::TARG_MACX_MODE) &&
453 inc[0] != '/')) {
454 for(MakefileDependDir *mdd = dirs.first(); mdd; mdd = dirs.next() ) {
455 if(!stat(mdd->local_dir + QDir::separator() + inc, &fst) &&
456 !S_ISDIR(fst.st_mode)) {
457 fqn = mdd->real_dir + QDir::separator() + inc;
458 goto handle_fqn;
459 }
460 }
461 }
462 }
463 if(fqn.isEmpty() && Option::mkfile::do_dep_heuristics) {
464 //these are some hacky heuristics it will try to do on an include
465 //however these can be turned off at runtime, I'm not sure how
466 //reliable these will be, most likely when problems arise turn it off
467 //and see if they go away..
468 if(depHeuristics.contains(inc)) {
469 fqn = depHeuristics[inc];
470 from_source_dir = FALSE;
471 } else if(Option::mkfile::do_dep_heuristics) { //some heuristics..
472 //is it a file from a .ui?
473 QString inc_file = inc.section(Option::dir_sep, -1);
474 int extn = inc_file.findRev('.');
475 if(extn != -1 &&
476 (inc_file.right(inc_file.length()-extn) == Option::cpp_ext.first() ||
477 inc_file.right(inc_file.length()-extn) == Option::h_ext.first())) {
478 QString uip = inc_file.left(extn) + Option::ui_ext;
479 QStringList uil = project->variables()["FORMS"];
480 for(QStringList::Iterator it = uil.begin(); it != uil.end(); ++it) {
481 if((*it).section(Option::dir_sep, -1) == uip) {
482 if(!project->isEmpty("UI_DIR"))
483 fqn = project->first("UI_DIR");
484 else if(!project->isEmpty("UI_HEADERS_DIR"))
485 fqn = project->first("UI_HEADERS_DIR");
486 else
487 fqn = (*it).section(Option::dir_sep, 0, -2);
488 if(!fqn.isEmpty() && !fqn.endsWith(Option::dir_sep))
489 fqn += Option::dir_sep;
490 fqn += inc_file;
491 from_source_dir = FALSE; //uics go in the output_dir (so don't fix them)
492 fqn = fileFixify(fqn, QDir::currentDirPath(), Option::output_dir);
493 goto cache_fqn;
494 }
495 }
496 }
497 if(project->isActiveConfig("lex_included")) { //is this the lex file?
498 QString rhs = Option::lex_mod + Option::cpp_ext.first();
499 if(inc.endsWith(rhs)) {
500 QString lhs = inc.left(inc.length() - rhs.length()) + Option::lex_ext;
501 QStringList ll = project->variables()["LEXSOURCES"];
502 for(QStringList::Iterator it = ll.begin(); it != ll.end(); ++it) {
503 QString s = (*it), d;
504 int slsh = s.findRev(Option::dir_sep);
505 if(slsh != -1) {
506 d = s.left(slsh + 1);
507 s = s.right(s.length() - slsh - 1);
508 }
509 if(!project->isEmpty("QMAKE_ABSOLUTE_SOURCE_PATH"))
510 d = project->first("QMAKE_ABSOLUTE_SOURCE_PATH");
511 if(s == lhs) {
512 fqn = d + inc;
513 from_source_dir = FALSE; //uics go in the output_dir (so don't fix them)
514 fqn = fileFixify(fqn, QDir::currentDirPath(), Option::output_dir);
515 goto cache_fqn;
516 }
517 }
518 }
519 }
520 { //is it from a .y?
521 QString rhs = Option::yacc_mod + Option::h_ext.first();
522 if(inc.endsWith(rhs)) {
523 QString lhs = inc.left(inc.length() - rhs.length()) + Option::yacc_ext;
524 QStringList yl = project->variables()["YACCSOURCES"];
525 for(QStringList::Iterator it = yl.begin(); it != yl.end(); ++it) {
526 QString s = (*it), d;
527 int slsh = s.findRev(Option::dir_sep);
528 if(slsh != -1) {
529 d = s.left(slsh + 1);
530 s = s.right(s.length() - slsh - 1);
531 }
532 if(!project->isEmpty("QMAKE_ABSOLUTE_SOURCE_PATH"))
533 d = project->first("QMAKE_ABSOLUTE_SOURCE_PATH");
534 if(s == lhs) {
535 fqn = d + inc;
536 from_source_dir = FALSE; //uics go in the output_dir (so don't fix them)
537 fqn = fileFixify(fqn, QDir::currentDirPath(), Option::output_dir);
538 goto cache_fqn;
539 }
540 }
541 }
542 }
543 if( mocAware() && //is it a moc file?
544 ( inc.endsWith(Option::cpp_ext.first()) || inc.endsWith(Option::cpp_moc_ext) )
545 || ( (Option::cpp_ext.first() != Option::h_moc_ext) && inc.endsWith(Option::h_moc_ext) )) {
546 QString mocs[] = { QString("_HDRMOC"), QString("_SRCMOC"), QString::null };
547 for(int moc = 0; !mocs[moc].isNull(); moc++) {
548 QStringList &l = project->variables()[mocs[moc]];
549 for(QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
550 QString file = Option::fixPathToTargetOS((*it));
551 if(file.section(Option::dir_sep, -(inc.contains('/')+1)) == inc) {
552 fqn = (*it);
553 if(mocs[moc] == "_HDRMOC") {
554 //Since it is include, no need to link it in as well
555 project->variables()["_SRCMOC"].append((*it));
556 l.remove(it);
557 } else if(!findMocSource(fqn).endsWith(fileFixify(fn))) {
558 /* Not really a very good test, but this will at least avoid
559 confusion if it really does happen (since tmake/qmake
560 previously didn't even allow this the test is mostly accurate) */
561 warn_msg(WarnLogic,
562 "Found potential multiple MOC include %s (%s) in '%s'",
563 inc.latin1(), fqn.latin1(), fix_env_fn.latin1());
564 }
565 from_source_dir = FALSE; //mocs go in the output_dir (so don't fix them)
566 goto cache_fqn;
567 }
568 }
569 }
570 }
571 fqn = findDependency(inc); //all else fails..
572 cache_fqn:
573 if(from_source_dir) {
574 fqn = fileFixify(fqn);
575 from_source_dir = FALSE;
576 }
577 depHeuristics.insert(inc, fqn);
578 }
579 }
580 handle_fqn:
581 if(fqn.isEmpty()) //I give up
582 continue;
583 fqn = Option::fixPathToTargetOS(fqn, FALSE);
584 if(from_source_dir)
585 fqn = fileFixify(fqn);
586 debug_msg(4, "Resolved dependency of %s to %s", inc.latin1(), fqn.latin1());
587 if(outdeps && outdeps->findIndex(fqn) == -1)
588 outdeps->append(fqn);
589 }
590 //read past new line now..
591 for( ; x < total_size_read && (*(big_buffer + x) != '\n'); x++);
592 line_count++;
593 }
594
595 if(recurse) {
596 for(QStringList::Iterator fnit = fndeps.begin(); fnit != fndeps.end(); ++fnit) {
597 generateDependencies(dirs, (*fnit), recurse);
598 QStringList &deplist = findDependencies((*fnit));
599 for(QStringList::Iterator it = deplist.begin(); it != deplist.end(); ++it)
600 if(fndeps.findIndex((*it)) == -1 && (*it) != fn)
601 fndeps.append((*it));
602 }
603 }
604 debug_msg(2, "Dependencies: %s -> %s", fn.latin1(), fndeps.join(" :: ").latin1());
605 return TRUE;
606}
607
608void
609MakefileGenerator::initOutPaths()
610{
611 if(init_opath_already)
612 return;
613 init_opath_already = TRUE;
614 QMap<QString, QStringList> &v = project->variables();
615 if(!v.contains("QMAKE_ABSOLUTE_SOURCE_PATH")) {
616 if(Option::mkfile::do_cache && !Option::mkfile::cachefile.isEmpty() &&
617 v.contains("QMAKE_ABSOLUTE_SOURCE_ROOT")) {
618 QString root = v["QMAKE_ABSOLUTE_SOURCE_ROOT"].first();
619 root = Option::fixPathToTargetOS( root );
620 if(!root.isEmpty()) {
621 QFileInfo fi(Option::mkfile::cachefile);
622 if(!fi.convertToAbs()) {
623 QString cache_r = fi.dirPath(), pwd = Option::output_dir;
624 if ( pwd.startsWith(cache_r) && !pwd.startsWith(root) ) {
625 pwd = Option::fixPathToTargetOS(root + pwd.mid(cache_r.length()));
626 if(QFile::exists(pwd))
627 v.insert("QMAKE_ABSOLUTE_SOURCE_PATH", pwd);
628 }
629 }
630 }
631 }
632 }
633 if(!v["QMAKE_ABSOLUTE_SOURCE_PATH"].isEmpty()) {
634 QString &asp = v["QMAKE_ABSOLUTE_SOURCE_PATH"].first();
635 asp = Option::fixPathToTargetOS( asp );
636 if(asp.isEmpty() || asp == Option::output_dir) //if they're the same, why bother?
637 v["QMAKE_ABSOLUTE_SOURCE_PATH"].clear();
638 }
639 QString currentDir = QDir::currentDirPath();
640 QString dirs[] = { QString("OBJECTS_DIR"), QString("MOC_DIR"), QString("UI_HEADERS_DIR"),
641 QString("UI_SOURCES_DIR"), QString("UI_DIR"), QString("DESTDIR"),
642 QString("SUBLIBS_DIR"), QString("DLLDESTDIR"), QString::null };
643 for(int x = 0; dirs[x] != QString::null; x++) {
644 if ( !v[dirs[x]].isEmpty() ) {
645 QString orig_path = v[dirs[x]].first();
646#ifdef Q_WS_WIN
647 // We don't want to add a separator for DLLDESTDIR on Windows
648 if (!(dirs[x] == "DLLDESTDIR"))
649#endif
650 {
651 QString &path = v[dirs[x]].first();
652 path = fileFixify(path, Option::output_dir, Option::output_dir);
653 if(path.right(Option::dir_sep.length()) != Option::dir_sep)
654 path += Option::dir_sep;
655 }
656 if(noIO())
657 continue;
658
659 QString path = project->first(dirs[x]); //not to be changed any further
660 path = Option::fixPathToTargetOS(fileFixify(path, QDir::currentDirPath(), Option::output_dir));
661 debug_msg(3, "Fixed output_dir %s (%s) into %s (%s)", dirs[x].latin1(), orig_path.latin1(),
662 v[dirs[x]].join("::").latin1(), path.latin1());
663
664 QDir d;
665 if(path.startsWith(Option::dir_sep)) {
666 d.cd(Option::dir_sep);
667 path = path.right(path.length() - 1);
668 }
669#ifdef Q_WS_WIN
670 bool driveExists = TRUE;
671 if ( !QDir::isRelativePath( path ) ) {
672 if ( QFile::exists( path.left( 3 ) ) ) {
673 d.cd( path.left( 3 ) );
674 path = path.right( path.length() - 3 );
675 } else {
676 warn_msg(WarnLogic, "%s: Cannot access drive '%s' (%s)", dirs[x].latin1(),
677 path.left( 3 ).latin1(), path.latin1() );
678 driveExists = FALSE;
679 }
680 }
681 if ( driveExists ) {
682#endif
683 QStringList subs = QStringList::split(Option::dir_sep, path);
684 for(QStringList::Iterator subit = subs.begin(); subit != subs.end(); ++subit) {
685 if(!d.cd(*subit)) {
686 d.mkdir((*subit));
687 if ( d.exists( (*subit) ) )
688 d.cd((*subit));
689 else {
690 warn_msg(WarnLogic, "%s: Cannot access directory '%s' (%s)", dirs[x].latin1(),
691 (*subit).latin1(), path.latin1() );
692 break;
693 }
694 }
695 }
696#ifdef Q_WS_WIN
697 }
698#endif
699 }
700 }
701 if ( !v["DESTDIR"].isEmpty() ) {
702 QDir d(v["DESTDIR"].first());
703 if(Option::fixPathToLocalOS(d.absPath()) == Option::fixPathToLocalOS(Option::output_dir))
704 v.remove("DESTDIR");
705 }
706 QDir::current().cd( currentDir );
707}
708
709void
710MakefileGenerator::init()
711{
712 initOutPaths();
713 if(init_already)
714 return;
715 init_already = TRUE;
716
717 QMap<QString, QStringList> &v = project->variables();
718 QString paths[] = { QString("SOURCES"), QString("FORMS"), QString("YACCSOURCES"), QString("INCLUDEPATH"),
719 QString("HEADERS"), QString("HEADERS_ORIG"), QString("LEXSOURCES"),
720 QString("QMAKE_INTERNAL_INCLUDED_FILES"),
721 QString("PRECOMPILED_HEADER"), QString::null };
722 for(int y = 0; paths[y] != QString::null; y++) {
723 QStringList &l = v[paths[y]];
724 for(QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
725 if ((*it).isEmpty())
726 continue;
727 if(QFile::exists((*it)))
728 (*it) = fileFixify((*it));
729 }
730 }
731
732 /* get deps and mocables */
733 QDict<void> cache_found_files;
734 QString cache_file(".qmake.internal.cache");
735 if(!project->isEmpty("QMAKE_INTERNAL_CACHE_FILE"))
736 cache_file = Option::fixPathToLocalOS(project->first("QMAKE_INTERNAL_CACHE_FILE"));
737 if(cache_file.find(QDir::separator()) == -1) //guess they know what they are doing..
738 cache_file.prepend(Option::output_dir + QDir::separator());
739 if((Option::qmake_mode == Option::QMAKE_GENERATE_PROJECT ||
740 Option::mkfile::do_deps || Option::mkfile::do_mocs) && !noIO()) {
741 QPtrList<MakefileDependDir> deplist;
742 deplist.setAutoDelete(TRUE);
743 if((Option::qmake_mode == Option::QMAKE_GENERATE_PROJECT || Option::mkfile::do_deps) &&
744 doDepends()) {
745 QStringList incDirs = v["DEPENDPATH"] + v["QMAKE_ABSOLUTE_SOURCE_PATH"];
746 if(project->isActiveConfig("depend_includepath"))
747 incDirs += v["INCLUDEPATH"];
748 for(QStringList::Iterator it = incDirs.begin(); it != incDirs.end(); ++it) {
749 QString r = (*it), l = Option::fixPathToLocalOS((*it));
750 deplist.append(new MakefileDependDir(r.replace("\"",""),
751 l.replace("\"","")));
752 }
753 debug_msg(1, "Dependency Directories: %s", incDirs.join(" :: ").latin1());
754 if(Option::output.name() != "-" && project->isActiveConfig("qmake_cache")) {
755 QFile cachef(cache_file);
756 if(cachef.open(IO_ReadOnly | IO_Translate)) {
757 QFileInfo cachefi(cache_file);
758 debug_msg(2, "Trying internal cache information: %s", cache_file.latin1());
759 QTextStream cachet(&cachef);
760 QString line, file;
761 enum { CacheInfo, CacheDepend, CacheMoc } state = CacheInfo;
762 while (!cachet.eof()) {
763 line = cachet.readLine().stripWhiteSpace();
764 int sep = line.find('=');
765 if(line == "[depend]") {
766 state = CacheDepend;
767 } else if(line == "[mocable]") {
768 state = CacheMoc;
769 } else if(line == "[check]") {
770 state = CacheInfo;
771 } else if(!line.isEmpty() && sep != -1) {
772 file = line.left(sep).stripWhiteSpace();
773 line = line.right(line.length() - sep - 1).stripWhiteSpace();
774 if(state == CacheInfo) {
775 if(file == "QMAKE_CACHE_VERSION") {
776 if(line != qmake_version())
777 break;
778 } else {
779 const QStringList &l = project->variables()[file];
780 if(!l.isEmpty() && !line.isEmpty() && l.join(" ") != line)
781 break;
782 }
783 } else if(state == CacheDepend) {
784 bool found = (bool)cache_found_files[file];
785 QStringList files = QStringList::split(" ", line);
786 if(!found) {
787 QFileInfo fi(fileFixify(file, QDir::currentDirPath(), Option::output_dir));
788 if(fi.exists() && fi.lastModified() < cachefi.lastModified()) {
789 cache_found_files.insert(file, (void *)1);
790 found = TRUE;
791 }
792 }
793 if(found) {
794 for(QStringList::Iterator dep_it = files.begin();
795 dep_it != files.end(); ++dep_it) {
796 if(!cache_found_files[(*dep_it)]) {
797 QFileInfo fi(fileFixify((*dep_it), QDir::currentDirPath(), Option::output_dir));
798 if(fi.exists() &&
799 fi.lastModified() < cachefi.lastModified()) {
800 cache_found_files.insert((*dep_it), (void *)1);
801 } else {
802 found = FALSE;
803 break;
804 }
805 }
806 }
807 if(found) {
808 debug_msg(2, "Dependencies (cached): %s -> %s", file.latin1(),
809 files.join(" :: ").latin1());
810 findDependencies(file) = files;
811 setProcessedDependencies(file, TRUE);
812 }
813 }
814 } else {
815 void *found = cache_found_files[file];
816 if(found != (void *)2) {
817 if(found) {
818 cache_found_files.replace(file, (void *)2);
819 } else {
820 QFileInfo fi(fileFixify(file, QDir::currentDirPath(), Option::output_dir));
821 if(fi.exists() && fi.lastModified() < cachefi.lastModified()) {
822 cache_found_files.insert(file, (void *)2);
823 found = (void*)1;
824 }
825 }
826 }
827 if(found && line != "*qmake_ignore*") {
828 int ext_len = file.length() - file.findRev('.');
829 bool cpp_ext = FALSE;
830 for(QStringList::Iterator cppit = Option::cpp_ext.begin();
831 cppit != Option::cpp_ext.end(); ++cppit) {
832 if((cpp_ext = (file.right(ext_len) == (*cppit))))
833 break;
834 }
835 if(cpp_ext) {
836 project->variables()["_SRCMOC"].append(line);
837 } else if(project->variables()["HEADERS"].findIndex(file) != -1) {
838 for(QStringList::Iterator hit = Option::h_ext.begin();
839 hit != Option::h_ext.end(); ++hit) {
840 if((file.right(ext_len) == (*hit))) {
841 project->variables()["_HDRMOC"].append(line);
842 break;
843 }
844 }
845 }
846 debug_msg(2, "Mocgen (cached): %s -> %s", file.latin1(),
847 line.latin1());
848 mocablesToMOC[file] = line;
849 mocablesFromMOC[line] = file;
850 }
851 }
852 }
853 }
854 cachef.close();
855 }
856 }
857 }
858 if(!noIO()) {
859 QString sources[] = { QString("OBJECTS"), QString("LEXSOURCES"), QString("YACCSOURCES"),
860 QString("HEADERS"), QString("SOURCES"), QString("FORMS"),
861 QString("PRECOMPILED_HEADER"), QString::null };
862 depHeuristics.clear();
863 bool write_cache = FALSE, read_cache = QFile::exists(cache_file);
864 int x;
865 for(x = 0; sources[x] != QString::null; x++) {
866 QStringList vpath, &l = v[sources[x]];
867 for(QStringList::Iterator val_it = l.begin(); val_it != l.end(); ++val_it) {
868 if(!(*val_it).isEmpty()) {
869 QString file = fileFixify((*val_it), QDir::currentDirPath(), Option::output_dir);
870 if(!QFile::exists(file)) {
871 bool found = FALSE;
872 if(QDir::isRelativePath((*val_it))) {
873 if(vpath.isEmpty())
874 vpath = v["VPATH_" + sources[x]] + v["VPATH"] +
875 v["QMAKE_ABSOLUTE_SOURCE_PATH"] + v["DEPENDPATH"];
876
877 for(QStringList::Iterator vpath_it = vpath.begin();
878 vpath_it != vpath.end(); ++vpath_it) {
879 QString real_dir = Option::fixPathToLocalOS((*vpath_it));
880 if(QFile::exists(real_dir + QDir::separator() + (*val_it))) {
881 QString dir = (*vpath_it);
882 if(dir.right(Option::dir_sep.length()) != Option::dir_sep)
883 dir += Option::dir_sep;
884 (*val_it) = fileFixify(dir + (*val_it));
885 found = TRUE;
886 debug_msg(1, "Found file through vpath %s -> %s",
887 file.latin1(), (*val_it).latin1());
888 break;
889 }
890 }
891 }
892 if(!found) {
893 QString dir, regex = (*val_it), real_dir;
894 if(regex.findRev(Option::dir_sep) != -1) {
895 dir = regex.left(regex.findRev(Option::dir_sep) + 1);
896 real_dir = fileFixify(Option::fixPathToLocalOS(dir),
897 QDir::currentDirPath(), Option::output_dir);
898 regex = regex.right(regex.length() - dir.length());
899 }
900 if(real_dir.isEmpty() || QFile::exists(real_dir)) {
901 QDir d(real_dir, regex);
902 if(!d.count()) {
903 debug_msg(1, "%s:%d Failure to find %s in vpath (%s)",
904 __FILE__, __LINE__,
905 (*val_it).latin1(), vpath.join("::").latin1());
906 warn_msg(WarnLogic, "Failure to find: %s", (*val_it).latin1());
907 continue;
908 } else {
909 for(int i = 0; i < (int)d.count(); i++) {
910 QString file = fileFixify(dir + d[i]);
911 if(i == (int)d.count() - 1)
912 (*val_it) = file;
913 else
914 l.insert(val_it, file);
915 }
916 }
917 } else {
918 debug_msg(1, "%s:%d Cannot match %s%c%s, as %s does not exist.",
919 __FILE__, __LINE__,
920 real_dir.latin1(), QDir::separator(), regex.latin1(),
921 real_dir.latin1());
922 warn_msg(WarnLogic, "Failure to find: %s", (*val_it).latin1());
923 }
924 }
925 }
926 }
927 }
928 }
929 for(x = 0; sources[x] != QString::null; x++) {
930 QStringList &l = v[sources[x]];
931 for(QStringList::Iterator val_it = l.begin(); val_it != l.end(); ++val_it) {
932 bool found_cache_moc = FALSE, found_cache_dep = FALSE;
933 if(read_cache && Option::output.name() != "-" &&
934 project->isActiveConfig("qmake_cache")) {
935 if(processedDependencies((*val_it)))
936 found_cache_dep = TRUE;
937 if(cache_found_files[(*val_it)] == (void *)2)
938 found_cache_moc = TRUE;
939 if(!found_cache_moc || !found_cache_dep)
940 write_cache = TRUE;
941 }
942 /* Do moc before dependency checking since some includes can come from
943 moc_*.cpp files */
944 if(found_cache_moc) {
945 QString fixed_file(fileFixify((*val_it), QDir::currentDirPath(), Option::output_dir));
946 QString moc = findMocDestination(fixed_file);
947 if(!moc.isEmpty()) {
948 for(QStringList::Iterator cppit = Option::cpp_ext.begin();
949 cppit != Option::cpp_ext.end(); ++cppit) {
950 if(fixed_file.endsWith((*cppit))) {
951 QStringList &deps = findDependencies(fixed_file);
952 if(!deps.contains(moc))
953 deps.append(moc);
954 break;
955 }
956 }
957 }
958 } else if(mocAware() && (sources[x] == "SOURCES" || sources[x] == "HEADERS") &&
959 (Option::qmake_mode == Option::QMAKE_GENERATE_PROJECT ||
960 Option::mkfile::do_mocs)) {
961 generateMocList((*val_it));
962 }
963 if(!found_cache_dep && sources[x] != "OBJECTS") {
964 debug_msg(5, "Looking for dependencies for %s", (*val_it).latin1());
965 generateDependencies(deplist, (*val_it), doDepends());
966 }
967 }
968 }
969 if(project->isActiveConfig("qmake_cache") && (write_cache || !read_cache)) {
970 QFile cachef(cache_file);
971 if(cachef.open(IO_WriteOnly | IO_Translate)) {
972 debug_msg(2, "Writing internal cache information: %s", cache_file.latin1());
973 QTextStream cachet(&cachef);
974 cachet << "[check]" << "\n"
975 << "QMAKE_CACHE_VERSION = " << qmake_version() << "\n"
976 << "QMAKE_ABSOLUTE_SOURCE_PATH = " << var("QMAKE_ABSOLUTE_SOURCE_PATH") << "\n"
977 << "MOC_DIR = " << var("MOC_DIR") << "\n"
978 << "UI_DIR = " << var("UI_DIR") << "\n"
979 << "UI_HEADERS_DIR = " << var("UI_HEADERS_DIR") << "\n"
980 << "UI_SOURCES_DIR = " << var("UI_SOURCES_DIR") << "\n";
981 cachet << "[depend]" << endl;
982 for(QMap<QString, QStringList>::Iterator it = depends.begin();
983 it != depends.end(); ++it)
984 cachet << dependencyKey(it.key()) << " = " << it.data().join(" ") << endl;
985 cachet << "[mocable]" << endl;
986 QString mc, moc_sources[] = { QString("HEADERS"), QString("SOURCES"), QString::null };
987 for(int x = 0; moc_sources[x] != QString::null; x++) {
988 QStringList &l = v[moc_sources[x]];
989 for(QStringList::Iterator val_it = l.begin(); val_it != l.end(); ++val_it) {
990 QString f = fileFixify((*val_it));
991 if(!f.isEmpty()) {
992 mc = mocablesToMOC[f];
993 if(mc.isEmpty())
994 mc = "*qmake_ignore*";
995 cachet << f << " = " << mc << endl;
996 }
997 }
998 }
999 cachef.close();
1000 }
1001 }
1002 }
1003 }
1004 v["OBJECTS"] = createObjectList("SOURCES") + v["OBJECTS"]; // init variables
1005
1006 //lex files
1007 {
1008 QStringList &impls = v["LEXIMPLS"];
1009 QStringList &l = v["LEXSOURCES"];
1010 for(QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
1011 QString dir;
1012 QFileInfo fi((*it));
1013 if(fi.dirPath() != ".")
1014 dir = fi.dirPath() + Option::dir_sep;
1015 dir = fileFixify(dir, QDir::currentDirPath(), Option::output_dir);
1016 if(!dir.isEmpty() && dir.right(Option::dir_sep.length()) != Option::dir_sep)
1017 dir += Option::dir_sep;
1018 QString impl = dir + fi.baseName(TRUE) + Option::lex_mod + Option::cpp_ext.first();
1019 logicWarn(impl, "SOURCES");
1020 logicWarn(impl, "SOURCES");
1021 impls.append(impl);
1022 if( ! project->isActiveConfig("lex_included")) {
1023 v["SOURCES"].append(impl);
1024 // attribute deps of lex file to impl file
1025 QStringList &lexdeps = findDependencies((*it));
1026 QStringList &impldeps = findDependencies(impl);
1027 for(QStringList::ConstIterator d = lexdeps.begin(); d != lexdeps.end(); ++d) {
1028 if(!impldeps.contains(*d))
1029 impldeps.append(*d);
1030 }
1031 lexdeps.clear();
1032 }
1033 }
1034 if( ! project->isActiveConfig("lex_included"))
1035 v["OBJECTS"] += (v["LEXOBJECTS"] = createObjectList("LEXIMPLS"));
1036 }
1037 //yacc files
1038 {
1039 QStringList &decls = v["YACCCDECLS"], &impls = v["YACCIMPLS"];
1040 QStringList &l = v["YACCSOURCES"];
1041 for(QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
1042 QString dir;
1043 QFileInfo fi((*it));
1044 if(fi.dirPath() != ".")
1045 dir = fi.dirPath() + Option::dir_sep;
1046 dir = fileFixify(dir, QDir::currentDirPath(), Option::output_dir);
1047 if(!dir.isEmpty() && dir.right(Option::dir_sep.length()) != Option::dir_sep)
1048 dir += Option::dir_sep;
1049 QString impl = dir + fi.baseName(TRUE) + Option::yacc_mod + Option::cpp_ext.first();
1050 logicWarn(impl, "SOURCES");
1051 QString decl = dir + fi.baseName(TRUE) + Option::yacc_mod + Option::h_ext.first();
1052 logicWarn(decl, "HEADERS");
1053
1054 decls.append(decl);
1055 impls.append(impl);
1056 v["SOURCES"].append(impl);
1057 QStringList &impldeps = findDependencies(impl);
1058 impldeps.append(decl);
1059 // attribute deps of yacc file to impl file
1060 QStringList &yaccdeps = findDependencies((*it));
1061 for(QStringList::ConstIterator d = yaccdeps.begin(); d != yaccdeps.end(); ++d) {
1062 if(!impldeps.contains(*d))
1063 impldeps.append(*d);
1064 }
1065 if( project->isActiveConfig("lex_included")) {
1066 // is there a matching lex file ? Transfer its dependencies.
1067 QString lexsrc = fi.baseName(TRUE) + Option::lex_ext;
1068 if(fi.dirPath() != ".")
1069 lexsrc.prepend(fi.dirPath() + Option::dir_sep);
1070 if(v["LEXSOURCES"].findIndex(lexsrc) != -1) {
1071 QString trg = dir + fi.baseName(TRUE) + Option::lex_mod + Option::cpp_ext.first();
1072 impldeps.append(trg);
1073 impldeps += findDependencies(lexsrc);
1074 depends[lexsrc].clear();
1075 }
1076 }
1077 yaccdeps.clear();
1078 }
1079 v["OBJECTS"] += (v["YACCOBJECTS"] = createObjectList("YACCIMPLS"));
1080 }
1081
1082 //UI files
1083 {
1084 QStringList &includepath = project->variables()["INCLUDEPATH"];
1085 if(!project->isEmpty("UI_DIR"))
1086 includepath.append(project->first("UI_DIR"));
1087 else if(!project->isEmpty("UI_HEADERS_DIR"))
1088 includepath.append(project->first("UI_HEADERS_DIR"));
1089 QStringList &decls = v["UICDECLS"], &impls = v["UICIMPLS"];
1090 QStringList &l = v["FORMS"];
1091 for(QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
1092 QString impl, decl;
1093 QFileInfo fi(Option::fixPathToLocalOS((*it)));
1094 if ( !project->isEmpty("UI_DIR") ) {
1095 impl = decl = project->first("UI_DIR");
1096 QString d = fi.dirPath();
1097 if( d == ".")
1098 d = QDir::currentDirPath();
1099 d = fileFixify(d, QDir::currentDirPath(), Option::output_dir);
1100 if(!includepath.contains(d))
1101 includepath.append(d);
1102 } else {
1103 if(decl.isEmpty() && !project->isEmpty("UI_HEADERS_DIR"))
1104 decl = project->first("UI_HEADERS_DIR");
1105 if(!decl.isEmpty() || (project->isEmpty("UI_HEADERS_DIR") &&
1106 !project->isEmpty("UI_SOURCES_DIR")) ) {
1107 QString d = fi.dirPath();
1108 if( d == ".")
1109 d = QDir::currentDirPath();
1110 d = fileFixify(d, QDir::currentDirPath(), Option::output_dir);
1111 if(includepath.contains(d))
1112 includepath.append(d);
1113 }
1114 if(impl.isEmpty() && !project->isEmpty("UI_SOURCES_DIR"))
1115 impl = project->first("UI_SOURCES_DIR");
1116 if(fi.dirPath() != ".") {
1117 if(impl.isEmpty())
1118 impl = fi.dirPath() + Option::dir_sep;
1119 if(decl.isEmpty())
1120 decl = fi.dirPath() + Option::dir_sep;
1121 }
1122 }
1123 impl = fileFixify(impl, QDir::currentDirPath(), Option::output_dir);
1124 if(!impl.isEmpty() && !impl.endsWith(Option::dir_sep))
1125 impl += Option::dir_sep;
1126 impl += fi.baseName(TRUE) + Option::cpp_ext.first();
1127 if(Option::output_dir != QDir::currentDirPath() &&
1128 project->isEmpty("UI_DIR") && project->isEmpty("UI_HEADERS_DIR")) {
1129 QString decl_fixed = fileFixify(decl, QDir::currentDirPath(), Option::output_dir);
1130 if(!includepath.contains(decl_fixed))
1131 includepath.append(decl_fixed);
1132 if(!includepath.contains(decl))
1133 project->variables()["INCLUDEPATH"].append(decl);
1134 }
1135 decl = fileFixify(decl, QDir::currentDirPath(), Option::output_dir);
1136 if(!decl.isEmpty() && !decl.endsWith(Option::dir_sep))
1137 decl += Option::dir_sep;
1138 decl += fi.baseName(TRUE) + Option::h_ext.first();
1139 logicWarn(impl, "SOURCES");
1140 logicWarn(decl, "HEADERS");
1141 decls.append(decl);
1142 impls.append(impl);
1143 findDependencies(impl).append(decl);
1144
1145 QString mocable = Option::h_moc_mod + fi.baseName(TRUE) + Option::h_moc_ext;
1146 if(!v["MOC_DIR"].isEmpty())
1147 mocable.prepend(v["MOC_DIR"].first());
1148 else if(fi.dirPath() != ".")
1149 mocable.prepend(fi.dirPath() + Option::dir_sep);
1150 logicWarn(mocable, "SOURCES");
1151 mocablesToMOC[cleanFilePath(decl)] = mocable;
1152 mocablesFromMOC[cleanFilePath(mocable)] = decl;
1153 v["_UIMOC"].append(mocable);
1154 }
1155 v["OBJECTS"] += (v["UICOBJECTS"] = createObjectList("UICDECLS"));
1156 }
1157
1158 //Translation files
1159 if(!project->isEmpty("TRANSLATIONS")) {
1160 QStringList &trf = project->variables()["TRANSLATIONS"];
1161 for(QStringList::Iterator it = trf.begin(); it != trf.end(); ++it) {
1162 (*it) = Option::fixPathToLocalOS((*it));
1163 }
1164 }
1165
1166 //Image files
1167 if(!project->isEmpty("IMAGES")) {
1168 if(project->isEmpty("QMAKE_IMAGE_COLLECTION"))
1169 v["QMAKE_IMAGE_COLLECTION"].append("qmake_image_collection" + Option::cpp_ext.first());
1170 QString imgfile = project->first("QMAKE_IMAGE_COLLECTION");
1171 Option::fixPathToTargetOS(imgfile);
1172 if(!project->isEmpty("UI_DIR") || !project->isEmpty("UI_SOURCES_DIR")) {
1173 if(imgfile.find(Option::dir_sep) != -1)
1174 imgfile = imgfile.right(imgfile.findRev(Option::dir_sep) + 1);
1175 imgfile.prepend( (project->isEmpty("UI_DIR") ? project->first("UI_SOURCES_DIR") :
1176 project->first("UI_DIR")) );
1177 v["QMAKE_IMAGE_COLLECTION"] = QStringList(imgfile);
1178 }
1179 logicWarn(imgfile, "SOURCES");
1180 if(!noIO()) {
1181 QStringList &l = v["IMAGES"];
1182 for(QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
1183 if(!QFile::exists((*it))) {
1184 warn_msg(WarnLogic, "Failure to open: %s", (*it).latin1());
1185 continue;
1186 }
1187 findDependencies(imgfile).append(fileFixify((*it)));
1188 }
1189 }
1190 v["OBJECTS"] += (v["IMAGEOBJECTS"] = createObjectList("QMAKE_IMAGE_COLLECTION"));
1191 }
1192 if(Option::output_dir != QDir::currentDirPath())
1193 project->variables()["INCLUDEPATH"].append(fileFixify(Option::output_dir, Option::output_dir,
1194 Option::output_dir));
1195
1196 //moc files
1197 if ( mocAware() ) {
1198 if(!project->isEmpty("MOC_DIR"))
1199 project->variables()["INCLUDEPATH"].append(project->first("MOC_DIR"));
1200 if ( Option::h_moc_ext == Option::cpp_ext.first() )
1201 v["OBJMOC"] = createObjectList("_HDRMOC") + createObjectList("_UIMOC");
1202
1203 QStringList &l = v["SRCMOC"];
1204 l = v["_HDRMOC"] + v["_UIMOC"] + v["_SRCMOC"];
1205 for(QStringList::Iterator val_it = l.begin(); val_it != l.end(); ++val_it) {
1206 if(!(*val_it).isEmpty())
1207 (*val_it) = Option::fixPathToTargetOS((*val_it), FALSE);
1208 }
1209 }
1210
1211 QString fixpaths[] = { QString("PRE_TARGETDEPS"), QString("POST_TARGETDEPS"), QString::null };
1212 for(int path = 0; !fixpaths[path].isNull(); path++) {
1213 QStringList &l = v[fixpaths[path]];
1214 for(QStringList::Iterator val_it = l.begin(); val_it != l.end(); ++val_it) {
1215 if(!(*val_it).isEmpty())
1216 (*val_it) = Option::fixPathToTargetOS((*val_it), FALSE);
1217 }
1218 }
1219
1220 // Make sure the INCLUDEPATH doesn't contain any empty(/null) entries
1221 QStringList &ipl = project->variables()["INCLUDEPATH"];
1222 for(QStringList::Iterator ipl_it = ipl.begin(); ipl_it != ipl.end();) {
1223 if ((*ipl_it).isEmpty())
1224 ipl_it = ipl.remove(ipl_it);
1225 else
1226 ++ipl_it;
1227 }
1228}
1229
1230bool
1231MakefileGenerator::processPrlFile(QString &file)
1232{
1233 bool ret = FALSE, try_replace_file=FALSE;
1234 QString meta_file, orig_file = file;
1235 if(QMakeMetaInfo::libExists(file)) {
1236 try_replace_file = TRUE;
1237 meta_file = file;
1238 file = "";
1239 } else {
1240 QString tmp = file;
1241 int ext = tmp.findRev('.');
1242 if(ext != -1)
1243 tmp = tmp.left(ext);
1244 meta_file = tmp;
1245 }
1246 meta_file = fileFixify(meta_file);
1247 if(!QMakeMetaInfo::libExists(fileFixify(meta_file, QDir::currentDirPath(), Option::output_dir)) &&
1248 project->isActiveConfig("qt")) {
1249 QString stem = meta_file, dir, extn;
1250 int slsh = stem.findRev('/'), hadlib = 0;
1251 if(slsh != -1) {
1252 dir = stem.left(slsh + 1);
1253 stem = stem.right(stem.length() - slsh - 1);
1254 }
1255 if(stem.startsWith("lib")) {
1256 hadlib = 1;
1257 stem = stem.right(stem.length() - 3);
1258 }
1259 int dot = stem.find('.');
1260 if(dot != -1) {
1261 extn = stem.right(stem.length() - dot);
1262 stem = stem.left(dot);
1263 }
1264 if(stem == "qt" || stem == "qte" || stem == "qte-mt" || stem == "qt-mt") {
1265 if(stem.endsWith("-mt"))
1266 stem = stem.left(stem.length() - 3); //lose the -mt
1267 else
1268 stem += "-mt"; //try the thread case
1269 meta_file = dir;
1270 if(hadlib)
1271 meta_file += "lib";
1272 meta_file += stem + extn;
1273 try_replace_file = TRUE;
1274 }
1275 }
1276 QString real_meta_file = Option::fixPathToLocalOS(meta_file);
1277 if(project->variables()["QMAKE_PRL_INTERNAL_FILES"].findIndex(QMakeMetaInfo::findLib(meta_file)) != -1) {
1278 ret = TRUE;
1279 } else if(!meta_file.isEmpty()) {
1280 QString f = fileFixify(real_meta_file, QDir::currentDirPath(), Option::output_dir);
1281 if(QMakeMetaInfo::libExists(f)) {
1282 QMakeMetaInfo libinfo;
1283 debug_msg(1, "Processing PRL file: %s", real_meta_file.latin1());
1284 if(!libinfo.readLib(f)) {
1285 fprintf(stderr, "Error processing meta file: %s\n", real_meta_file.latin1());
1286 } else if(project->isActiveConfig("no_read_prl_" + libinfo.type().lower())) {
1287 debug_msg(2, "Ignored meta file %s [%s]", real_meta_file.latin1(), libinfo.type().latin1());
1288 } else {
1289 ret = TRUE;
1290 QMap<QString, QStringList> &vars = libinfo.variables();
1291 for( QMap<QString, QStringList>::Iterator it = vars.begin(); it != vars.end(); ++it)
1292 processPrlVariable(it.key(), it.data());
1293 if(try_replace_file && !libinfo.isEmpty("QMAKE_PRL_TARGET")) {
1294 QString dir;
1295 int slsh = real_meta_file.findRev(Option::dir_sep);
1296 if(slsh != -1)
1297 dir = real_meta_file.left(slsh+1);
1298 file = libinfo.first("QMAKE_PRL_TARGET");
1299 if(QDir::isRelativePath(file))
1300 file.prepend(dir);
1301 }
1302 }
1303 }
1304 if(ret) {
1305 QString mf = QMakeMetaInfo::findLib(meta_file);
1306 project->variables()["QMAKE_PRL_INTERNAL_FILES"].append(mf);
1307 project->variables()["QMAKE_INTERNAL_INCLUDED_FILES"].append(mf);
1308 }
1309 }
1310 if(try_replace_file && file.isEmpty()) {
1311#if 0
1312 warn_msg(WarnLogic, "Found prl [%s] file with no target [%s]!", meta_file.latin1(),
1313 orig_file.latin1());
1314#endif
1315 file = orig_file;
1316 }
1317 return ret;
1318}
1319
1320void
1321MakefileGenerator::processPrlVariable(const QString &var, const QStringList &l)
1322{
1323 if(var == "QMAKE_PRL_LIBS") {
1324 QString where = "QMAKE_LIBS";
1325 if(!project->isEmpty("QMAKE_INTERNAL_PRL_LIBS"))
1326 where = project->first("QMAKE_INTERNAL_PRL_LIBS");
1327 QStringList &out = project->variables()[where];
1328 for(QStringList::ConstIterator it = l.begin(); it != l.end(); ++it) {
1329 if( out.findIndex((*it)) == -1)
1330 out.append((*it));
1331 }
1332 } else if(var == "QMAKE_PRL_DEFINES") {
1333 QStringList &out = project->variables()["DEFINES"];
1334 for(QStringList::ConstIterator it = l.begin(); it != l.end(); ++it) {
1335 if(out.findIndex((*it)) == -1 &&
1336 project->variables()["PRL_EXPORT_DEFINES"].findIndex((*it)) == -1)
1337 out.append((*it));
1338 }
1339 }
1340}
1341
1342void
1343MakefileGenerator::processPrlFiles()
1344{
1345 QDict<void> processed;
1346 for(bool ret = FALSE; TRUE; ret = FALSE) {
1347 //read in any prl files included..
1348 QStringList l_out;
1349 QString where = "QMAKE_LIBS";
1350 if(!project->isEmpty("QMAKE_INTERNAL_PRL_LIBS"))
1351 where = project->first("QMAKE_INTERNAL_PRL_LIBS");
1352 QStringList &l = project->variables()[where];
1353 for(QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
1354 QString file = (*it);
1355 if(!processed[file] && processPrlFile(file)) {
1356 processed.insert(file, (void*)1);
1357 ret = TRUE;
1358 }
1359 if(!file.isEmpty())
1360 l_out.append(file);
1361 }
1362 if(ret)
1363 l = l_out;
1364 else
1365 break;
1366 }
1367}
1368
1369void
1370MakefileGenerator::writePrlFile(QTextStream &t)
1371{
1372 QString target = project->first("TARGET");
1373 int slsh = target.findRev(Option::dir_sep);
1374 if(slsh != -1)
1375 target = target.right(target.length() - slsh - 1);
1376 QString bdir = Option::output_dir;
1377 if(bdir.isEmpty())
1378 bdir = QDir::currentDirPath();
1379 t << "QMAKE_PRL_BUILD_DIR = " << bdir << endl;
1380
1381 if(!project->projectFile().isEmpty() && project->projectFile() != "-")
1382 t << "QMAKE_PRO_INPUT = " << project->projectFile().section('/', -1) << endl;
1383
1384 if(!project->isEmpty("QMAKE_ABSOLUTE_SOURCE_PATH"))
1385 t << "QMAKE_PRL_SOURCE_DIR = " << project->first("QMAKE_ABSOLUTE_SOURCE_PATH") << endl;
1386 t << "QMAKE_PRL_TARGET = " << target << endl;
1387 if(!project->isEmpty("PRL_EXPORT_DEFINES"))
1388 t << "QMAKE_PRL_DEFINES = " << project->variables()["PRL_EXPORT_DEFINES"].join(" ") << endl;
1389 if(!project->isEmpty("PRL_EXPORT_CFLAGS"))
1390 t << "QMAKE_PRL_CFLAGS = " << project->variables()["PRL_EXPORT_CFLAGS"].join(" ") << endl;
1391 if(!project->isEmpty("PRL_EXPORT_CXXFLAGS"))
1392 t << "QMAKE_PRL_CXXFLAGS = " << project->variables()["PRL_EXPORT_CXXFLAGS"].join(" ") << endl;
1393 if(!project->isEmpty("CONFIG"))
1394 t << "QMAKE_PRL_CONFIG = " << project->variables()["CONFIG"].join(" ") << endl;
1395 if(!project->isEmpty("VERSION"))
1396 t << "QMAKE_PRL_VERSION = " << project->first("VERSION") << endl;
1397 if(project->isActiveConfig("staticlib") || project->isActiveConfig("explicitlib")) {
1398 QStringList libs;
1399 if(!project->isEmpty("QMAKE_INTERNAL_PRL_LIBS"))
1400 libs = project->variables()["QMAKE_INTERNAL_PRL_LIBS"];
1401 else
1402 libs << "QMAKE_LIBS"; //obvious one
1403 t << "QMAKE_PRL_LIBS = ";
1404 for(QStringList::Iterator it = libs.begin(); it != libs.end(); ++it)
1405 t << project->variables()[(*it)].join(" ") << " ";
1406 t << endl;
1407 }
1408}
1409
1410bool
1411MakefileGenerator::write()
1412{
1413 usePlatformDir();
1414 init();
1415 findLibraries();
1416 if((Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE || //write prl
1417 Option::qmake_mode == Option::QMAKE_GENERATE_PRL) &&
1418 project->variables()["QMAKE_FAILED_REQUIREMENTS"].isEmpty() &&
1419 project->isActiveConfig("create_prl") && project->first("TEMPLATE") == "lib" &&
1420 !project->isActiveConfig("plugin")) {
1421 QString prl = var("TARGET");
1422 int slsh = prl.findRev(Option::dir_sep);
1423 if(slsh != -1)
1424 prl = prl.right(prl.length() - slsh);
1425 int dot = prl.find('.');
1426 if(dot != -1)
1427 prl = prl.left(dot);
1428 prl += Option::prl_ext;
1429 if(!project->isEmpty("DESTDIR"))
1430 prl.prepend(var("DESTDIR"));
1431 QString local_prl = Option::fixPathToLocalOS(fileFixify(prl, QDir::currentDirPath(), Option::output_dir));
1432 QFile ft(local_prl);
1433 if(ft.open(IO_WriteOnly)) {
1434 project->variables()["ALL_DEPS"].append(prl);
1435 project->variables()["QMAKE_INTERNAL_PRL_FILE"].append(prl);
1436 QTextStream t(&ft);
1437 writePrlFile(t);
1438 ft.close();
1439 }
1440 }
1441 if(Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE &&
1442 project->isActiveConfig("link_prl")) //load up prl's'
1443 processPrlFiles();
1444
1445 if(Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE || //write prl file
1446 Option::qmake_mode == Option::QMAKE_GENERATE_PROJECT) {
1447 QTextStream t(&Option::output);
1448 writeMakefile(t);
1449 }
1450 return TRUE;
1451}
1452
1453// Manipulate directories, so it's possible to build
1454// several cross-platform targets concurrently
1455void
1456MakefileGenerator::usePlatformDir()
1457{
1458 QString pltDir(project->first("QMAKE_PLATFORM_DIR"));
1459 if(pltDir.isEmpty())
1460 return;
1461 char sep = QDir::separator();
1462 QString slashPltDir = sep + pltDir;
1463
1464 QString filePath = project->first("DESTDIR");
1465 project->variables()["DESTDIR"] = filePath
1466 + (filePath.isEmpty() ? pltDir : slashPltDir);
1467
1468 filePath = project->first("DLLDESTDIR");
1469 project->variables()["DLLDESTDIR"] = filePath
1470 + (filePath.isEmpty() ? pltDir : slashPltDir);
1471
1472 filePath = project->first("OBJECTS_DIR");
1473 project->variables()["OBJECTS_DIR"] = filePath
1474 + (filePath.isEmpty() ? pltDir : slashPltDir);
1475
1476 filePath = project->first("QMAKE_LIBDIR_QT");
1477 project->variables()["QMAKE_LIBDIR_QT"] = filePath
1478 + (filePath.isEmpty() ? pltDir : slashPltDir);
1479
1480 filePath = project->first("QMAKE_LIBS_QT");
1481 int fpi = filePath.findRev(sep);
1482 if (fpi == -1)
1483 project->variables()["QMAKE_LIBS_QT"].prepend(pltDir + sep);
1484 else
1485 project->variables()["QMAKE_LIBS_QT"] = filePath.left(fpi)
1486 + slashPltDir
1487 + filePath.mid(fpi);
1488
1489 filePath = project->first("QMAKE_LIBS_QT_THREAD");
1490 fpi = filePath.findRev(sep);
1491 if (fpi == -1)
1492 project->variables()["QMAKE_LIBS_QT_THREAD"].prepend(pltDir + sep);
1493 else
1494 project->variables()["QMAKE_LIBS_QT_THREAD"] = filePath.left(fpi)
1495 + slashPltDir
1496 + filePath.mid(fpi);
1497
1498 filePath = project->first("QMAKE_LIBS_QT_ENTRY");
1499 fpi = filePath.findRev(sep);
1500 if (fpi == -1)
1501 project->variables()["QMAKE_LIBS_QT_ENTRY"].prepend(pltDir + sep);
1502 else
1503 project->variables()["QMAKE_LIBS_QT_ENTRY"] = filePath.left(fpi)
1504 + slashPltDir
1505 + filePath.mid(fpi);
1506}
1507
1508void
1509MakefileGenerator::writeObj(QTextStream &t, const QString &obj, const QString &src)
1510{
1511 QStringList &objl = project->variables()[obj];
1512 QStringList &srcl = project->variables()[src];
1513
1514 QStringList::Iterator oit = objl.begin();
1515 QStringList::Iterator sit = srcl.begin();
1516 QString stringSrc("$src");
1517 QString stringObj("$obj");
1518 for( ;sit != srcl.end() && oit != objl.end(); oit++, sit++) {
1519 if((*sit).isEmpty())
1520 continue;
1521
1522 if(!doDepends()) {
1523 QString sdep, odep = (*sit) + " ";
1524 QStringList deps = findDependencies((*sit));
1525 for(QStringList::Iterator dit = deps.begin(); dit != deps.end(); dit++) {
1526 if((*dit).endsWith(Option::cpp_moc_ext))
1527 odep += (*dit) + " ";
1528 else
1529 sdep += (*dit) + " ";
1530 }
1531 t << (*sit) << ": " << sdep << endl
1532 << (*oit) << ": " << odep ;
1533 } else {
1534 t << (*oit) << ": " << (*sit) << " " << findDependencies((*sit)).join(" \\\n\t\t");
1535 }
1536
1537 QString comp, cimp;
1538 for(QStringList::Iterator cppit = Option::cpp_ext.begin(); cppit != Option::cpp_ext.end(); ++cppit) {
1539 if((*sit).endsWith((*cppit))) {
1540 comp = "QMAKE_RUN_CXX";
1541 cimp = "QMAKE_RUN_CXX_IMP";
1542 break;
1543 }
1544 }
1545 if(comp.isEmpty()) {
1546 comp = "QMAKE_RUN_CC";
1547 cimp = "QMAKE_RUN_CC_IMP";
1548 }
1549 bool use_implicit_rule = !project->isEmpty(cimp) && !project->isActiveConfig("compile_absolute_path");
1550 if(use_implicit_rule) {
1551 if(!project->isEmpty("OBJECTS_DIR")) {
1552 use_implicit_rule = FALSE;
1553 } else {
1554 int dot = (*sit).findRev('.');
1555 if(dot == -1 || ((*sit).left(dot) + Option::obj_ext != (*oit)))
1556 use_implicit_rule = FALSE;
1557 }
1558 }
1559 if (!use_implicit_rule && !project->isEmpty(comp)) {
1560 QString p = var(comp), srcf(*sit);
1561 if(project->isActiveConfig("compile_absolute_path") && QDir::isRelativePath(srcf))
1562 srcf.prepend("$(PWD)" + Option::dir_sep);
1563 p.replace(stringSrc, srcf);
1564 p.replace(stringObj, (*oit));
1565 t << "\n\t" << p;
1566 }
1567 t << endl << endl;
1568 }
1569}
1570
1571
1572void
1573MakefileGenerator::writeUicSrc(QTextStream &t, const QString &ui)
1574{
1575 QStringList &uil = project->variables()[ui];
1576 for(QStringList::Iterator it = uil.begin(); it != uil.end(); it++) {
1577 QString decl, impl;
1578 {
1579 QString tmp = (*it), impl_dir, decl_dir;
1580 decl = tmp.replace(QRegExp("\\" + Option::ui_ext + "$"), Option::h_ext.first());
1581 int dlen = decl.findRev(Option::dir_sep) + 1;
1582 tmp = (*it);
1583 impl = tmp.replace(QRegExp("\\" + Option::ui_ext + "$"), Option::cpp_ext.first());
1584 int ilen = decl.findRev(Option::dir_sep) + 1;
1585 if(!project->isEmpty("UI_DIR")) {
1586 impl_dir = project->first("UI_DIR");
1587 decl = project->first("UI_DIR") + decl.right(decl.length() - dlen);
1588 impl = project->first("UI_DIR") + impl.right(impl.length() - ilen);
1589 } else {
1590 if(!project->isEmpty("UI_HEADERS_DIR")) {
1591 decl_dir = project->first("UI_HEADERS_DIR");
1592 decl = project->first("UI_HEADERS_DIR") + decl.right(decl.length() - dlen);
1593 }
1594 if(!project->isEmpty("UI_SOURCES_DIR")) {
1595 impl_dir = project->first("UI_SOURCES_DIR");
1596 impl = project->first("UI_SOURCES_DIR") + impl.right(impl.length() - ilen);
1597 }
1598 }
1599 impl = fileFixify(impl, QDir::currentDirPath(), Option::output_dir);
1600 decl = fileFixify(decl, QDir::currentDirPath(), Option::output_dir);
1601 if(decl_dir.isEmpty())
1602 decl_dir = decl.section(Option::dir_sep,0,-2);
1603 if(impl_dir.isEmpty())
1604 impl_dir = impl.section(Option::dir_sep,0,-2);
1605 if (QDir::isRelativePath(impl_dir))
1606 impl_dir.prepend(Option::output_dir + Option::dir_sep);
1607 if (QDir::isRelativePath(decl_dir))
1608 decl_dir.prepend(Option::output_dir + Option::dir_sep);
1609 createDir(impl_dir);
1610 createDir(decl_dir);
1611 }
1612 QStringList deps = findDependencies((*it));
1613 deps.remove(decl); //avoid circular dependencies..
1614 t << decl << ": " << (*it) << " " << deps.join(" \\\n\t\t") << "\n\t"
1615 << "$(UIC) " << (*it) << " -o " << decl << endl << endl;
1616
1617 QString mildDecl = decl;
1618 int k = mildDecl.findRev(Option::dir_sep);
1619 if ( k != -1 )
1620 mildDecl = mildDecl.mid( k + 1 );
1621 t << impl << ": " << decl << " " << (*it) << " " << deps.join(" \\\n\t\t") << "\n\t"
1622 << "$(UIC)";
1623 t << " " << (*it) << " -i " << mildDecl << " -o " << impl << endl << endl;
1624 }
1625}
1626
1627
1628void
1629MakefileGenerator::writeMocObj(QTextStream &t, const QString &obj, const QString &src)
1630{
1631 QStringList &objl = project->variables()[obj],
1632 &srcl = project->variables()[src];
1633 QStringList::Iterator oit = objl.begin(), sit = srcl.begin();
1634 QString stringSrc("$src"), stringObj("$obj");
1635 for( ;sit != srcl.end() && oit != objl.end(); oit++, sit++) {
1636 QString hdr = findMocSource((*sit));
1637 t << (*oit) << ": "
1638 << (*sit) << " " << findDependencies((*sit)).join(" \\\n\t\t") << " "
1639 << hdr << " " << findDependencies(hdr).join(" \\\n\t\t");
1640 bool use_implicit_rule = !project->isEmpty("QMAKE_RUN_CXX_IMP") && !project->isActiveConfig("compile_absolute_path");
1641 if(use_implicit_rule) {
1642 if(!project->isEmpty("OBJECTS_DIR") || !project->isEmpty("MOC_DIR")) {
1643 use_implicit_rule = FALSE;
1644 } else {
1645 int dot = (*sit).findRev('.');
1646 if(dot == -1 || ((*sit).left(dot) + Option::obj_ext != (*oit)))
1647 use_implicit_rule = FALSE;
1648 }
1649 }
1650 if (!use_implicit_rule && !project->isEmpty("QMAKE_RUN_CXX")) {
1651 QString p = var("QMAKE_RUN_CXX"), srcf(*sit);
1652 if(project->isActiveConfig("compile_absolute_path") && QDir::isRelativePath(srcf))
1653 srcf.prepend("$(PWD)" + Option::dir_sep);
1654 p.replace(stringSrc, srcf);
1655 p.replace(stringObj, (*oit));
1656 t << "\n\t" << p;
1657 }
1658 t << endl << endl;
1659 }
1660}
1661
1662
1663void
1664MakefileGenerator::writeMocSrc(QTextStream &t, const QString &src)
1665{
1666 QStringList &l = project->variables()[src];
1667 for(QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
1668 QString m = Option::fixPathToTargetOS(findMocDestination(*it));
1669 if ( !m.isEmpty()) {
1670 QString deps;
1671 if(!project->isActiveConfig("no_mocdepend"))
1672 deps += "$(MOC) ";
1673 deps += (*it);
1674 t << m << ": " << deps << "\n\t"
1675 << "$(MOC)";
1676 t << " " << (*it) << " -o " << m << endl << endl;
1677 }
1678 }
1679}
1680
1681void
1682MakefileGenerator::writeYaccSrc(QTextStream &t, const QString &src)
1683{
1684 QStringList &l = project->variables()[src];
1685 if(project->isActiveConfig("yacc_no_name_mangle") && l.count() > 1)
1686 warn_msg(WarnLogic, "yacc_no_name_mangle specified, but multiple parsers expected."
1687 "This can lead to link problems.\n");
1688 QString default_out_h = "y.tab.h", default_out_c = "y.tab.c";
1689 if(!project->isEmpty("QMAKE_YACC_HEADER"))
1690 default_out_h = project->first("QMAKE_YACC_HEADER");
1691 if(!project->isEmpty("QMAKE_YACC_SOURCE"))
1692 default_out_c = project->first("QMAKE_YACC_SOURCE");
1693 QString stringBase("$base");
1694 for(QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
1695 QFileInfo fi((*it));
1696 QString dir;
1697 if(fi.dirPath() != ".")
1698 dir = fi.dirPath() + Option::dir_sep;
1699 dir = fileFixify(dir, QDir::currentDirPath(), Option::output_dir);
1700 if(!dir.isEmpty() && dir.right(Option::dir_sep.length()) != Option::dir_sep)
1701 dir += Option::dir_sep;
1702
1703 QString impl = dir + fi.baseName(TRUE) + Option::yacc_mod + Option::cpp_ext.first();
1704 QString decl = dir + fi.baseName(TRUE) + Option::yacc_mod + Option::h_ext.first();
1705
1706 QString yaccflags = "$(YACCFLAGS)", mangle = "y";
1707 if(!project->isActiveConfig("yacc_no_name_mangle")) {
1708 mangle = fi.baseName(TRUE);
1709 if(!project->isEmpty("QMAKE_YACCFLAGS_MANGLE"))
1710 yaccflags += " " + var("QMAKE_YACCFLAGS_MANGLE").replace(stringBase, mangle);
1711 else
1712 yaccflags += " -p " + mangle;
1713 }
1714 QString out_h = default_out_h, out_c = default_out_c;
1715 if(!mangle.isEmpty()) {
1716 out_h.replace(stringBase, mangle);
1717 out_c.replace(stringBase, mangle);
1718 }
1719
1720 t << impl << ": " << (*it) << "\n\t"
1721 << "$(YACC) " << yaccflags << " " << (*it) << "\n\t"
1722 << "-$(DEL_FILE) " << impl << " " << decl << "\n\t"
1723 << "-$(MOVE) " << out_h << " " << decl << "\n\t"
1724 << "-$(MOVE) " << out_c << " " << impl << endl << endl;
1725 t << decl << ": " << impl << endl << endl;
1726 }
1727}
1728
1729void
1730MakefileGenerator::writeLexSrc(QTextStream &t, const QString &src)
1731{
1732 QStringList &l = project->variables()[src];
1733 if(project->isActiveConfig("yacc_no_name_mangle") && l.count() > 1)
1734 warn_msg(WarnLogic, "yacc_no_name_mangle specified, but multiple parsers expected.\n"
1735 "This can lead to link problems.\n");
1736 QString default_out_c = "lex.$base.c";
1737 if(!project->isEmpty("QMAKE_LEX_SOURCE"))
1738 default_out_c = project->first("QMAKE_LEX_SOURCE");
1739 QString stringBase("$base");
1740 for(QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
1741 QFileInfo fi((*it));
1742 QString dir;
1743 if(fi.dirPath() != ".")
1744 dir = fi.dirPath() + Option::dir_sep;
1745 dir = fileFixify(dir, QDir::currentDirPath(), Option::output_dir);
1746 if(!dir.isEmpty() && dir.right(Option::dir_sep.length()) != Option::dir_sep)
1747 dir += Option::dir_sep;
1748 QString impl = dir + fi.baseName(TRUE) + Option::lex_mod + Option::cpp_ext.first();
1749
1750 QString lexflags = "$(LEXFLAGS)", stub="yy";
1751 if(!project->isActiveConfig("yacc_no_name_mangle")) {
1752 stub = fi.baseName(TRUE);
1753 lexflags += " -P" + stub;
1754 }
1755 QString out_c = default_out_c;
1756 if(!stub.isEmpty())
1757 out_c.replace(stringBase, stub);
1758
1759 t << impl << ": " << (*it) << " " << findDependencies((*it)).join(" \\\n\t\t") << "\n\t"
1760 << ( "$(LEX) " + lexflags + " " ) << (*it) << "\n\t"
1761 << "-$(DEL_FILE) " << impl << " " << "\n\t"
1762 << "-$(MOVE) " << out_c << " " << impl << endl << endl;
1763 }
1764}
1765
1766void
1767MakefileGenerator::writeImageObj(QTextStream &t, const QString &obj)
1768{
1769 QStringList &objl = project->variables()[obj];
1770 QString stringSrc("$src");
1771 QString stringObj("$obj");
1772
1773 QString uidir;
1774 for(QStringList::Iterator oit = objl.begin(); oit != objl.end(); oit++) {
1775 QString src(project->first("QMAKE_IMAGE_COLLECTION"));
1776 t << (*oit) << ": " << src;
1777 bool use_implicit_rule = !project->isEmpty("QMAKE_RUN_CXX_IMP") && !project->isActiveConfig("compile_absolute_path");
1778 if(use_implicit_rule) {
1779 if(!project->isEmpty("OBJECTS_DIR") || !project->isEmpty("UI_DIR") || !project->isEmpty("UI_SOURCES_DIR")) {
1780 use_implicit_rule = FALSE;
1781 } else {
1782 int dot = src.findRev('.');
1783 if(dot == -1 || (src.left(dot) + Option::obj_ext != (*oit)))
1784 use_implicit_rule = FALSE;
1785 }
1786 }
1787 if(!use_implicit_rule && !project->isEmpty("QMAKE_RUN_CXX")) {
1788 QString p = var("QMAKE_RUN_CXX"), srcf(src);
1789 if(project->isActiveConfig("compile_absolute_path") && QDir::isRelativePath(srcf))
1790 srcf.prepend("$(PWD)" + Option::dir_sep);
1791 p.replace(stringSrc, srcf);
1792 p.replace(stringObj, (*oit));
1793 t << "\n\t" << p;
1794 }
1795 t << endl << endl;
1796 }
1797}
1798
1799
1800void
1801MakefileGenerator::writeImageSrc(QTextStream &t, const QString &src)
1802{
1803 QStringList &l = project->variables()[src];
1804 for(QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
1805 QString gen = project->first("MAKEFILE_GENERATOR");
1806 if ( gen == "MSVC" ) {
1807 t << (*it) << ": " << findDependencies((*it)).join(" \\\n\t\t") << "\n\t"
1808 << "$(UIC) -o " << (*it) << " -embed " << project->first("QMAKE_ORIG_TARGET")
1809 << " -f <<\n" << findDependencies((*it)).join(" ") << "\n<<" << endl << endl;
1810 } else if ( gen == "BMAKE" ) {
1811 t << (*it) << ": " << findDependencies((*it)).join(" \\\n\t\t") << "\n\t"
1812 << "$(UIC) " << " -embed " << project->first("QMAKE_ORIG_TARGET")
1813 << " -f &&|\n" << findDependencies((*it)).join(" ") << "\n| -o " << (*it) << endl << endl;
1814 } else {
1815 t << (*it) << ": " << findDependencies((*it)).join(" \\\n\t\t") << "\n\t"
1816 << "$(UIC) " << " -embed " << project->first("QMAKE_ORIG_TARGET")
1817 << " " << findDependencies((*it)).join(" ") << " -o " << (*it) << endl << endl;
1818 }
1819 }
1820}
1821
1822
1823void
1824MakefileGenerator::writeInstalls(QTextStream &t, const QString &installs)
1825{
1826 QString all_installs, all_uninstalls;
1827 QStringList &l = project->variables()[installs];
1828 for(QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
1829 QString pvar = (*it) + ".path";
1830 if(project->variables()[(*it) + ".CONFIG"].findIndex("no_path") == -1 &&
1831 project->variables()[pvar].isEmpty()) {
1832 warn_msg(WarnLogic, "%s is not defined: install target not created\n", pvar.latin1());
1833 continue;
1834 }
1835
1836 bool do_default = TRUE;
1837 const QString root = "$(INSTALL_ROOT)";
1838 QString target, dst= fileFixify(project->variables()[pvar].first());
1839 if(dst.right(1) != Option::dir_sep)
1840 dst += Option::dir_sep;
1841 QStringList tmp, uninst = project->variables()[(*it) + ".uninstall"];
1842 //other
1843 tmp = project->variables()[(*it) + ".extra"];
1844 if(tmp.isEmpty())
1845 tmp = project->variables()[(*it) + ".commands"]; //to allow compatible name
1846 if(!tmp.isEmpty()) {
1847 do_default = FALSE;
1848 if(!target.isEmpty())
1849 target += "\n\t";
1850 target += tmp.join(" ");
1851 }
1852 //masks
1853 tmp = project->variables()[(*it) + ".files"];
1854 if(!tmp.isEmpty()) {
1855 if(!target.isEmpty())
1856 target += "\n";
1857 do_default = FALSE;
1858 for(QStringList::Iterator wild_it = tmp.begin(); wild_it != tmp.end(); ++wild_it) {
1859 QString wild = Option::fixPathToLocalOS((*wild_it), FALSE), wild_var = fileFixify(wild);
1860 QString dirstr = QDir::currentDirPath(), filestr = wild;
1861 int slsh = filestr.findRev(Option::dir_sep);
1862 if(slsh != -1) {
1863 dirstr = filestr.left(slsh+1);
1864 filestr = filestr.right(filestr.length() - slsh - 1);
1865 }
1866 if(dirstr.right(Option::dir_sep.length()) != Option::dir_sep)
1867 dirstr += Option::dir_sep;
1868 if(QFile::exists(wild)) { //real file
1869 QString file = wild;
1870 QFileInfo fi(wild);
1871 if(!target.isEmpty())
1872 target += "\t";
1873 QString cmd = QString(fi.isDir() ? "-$(INSTALL_DIR)" : "-$(INSTALL_FILE)") + " \"" +
1874 Option::fixPathToTargetOS(fileFixify(wild, QString::null,
1875 QString::null, FALSE, FALSE), FALSE) +
1876 "\" \"" + root + dst + "\"\n";
1877 target += cmd;
1878 if(!project->isActiveConfig("debug") &&
1879 !fi.isDir() && fi.isExecutable() && !project->isEmpty("QMAKE_STRIP"))
1880 target += QString("\t-") + var("QMAKE_STRIP") + " \"" +
1881 root + fileFixify(dst + filestr, QString::null, QString::null, FALSE, FALSE) +
1882 "\"\n";
1883 if(!uninst.isEmpty())
1884 uninst.append("\n\t");
1885 uninst.append(
1886#ifdef Q_WS_WIN
1887 QString("-$(DEL_FILE)")
1888#else
1889 QString("-$(DEL_FILE) -r")
1890#endif
1891 + " \"" + root + fileFixify(dst + filestr, QString::null, QString::null, FALSE, FALSE) + "\"");
1892 continue;
1893 }
1894 fixEnvVariables(dirstr);
1895 QDir dir(dirstr, filestr); //wild
1896 for(uint x = 0; x < dir.count(); x++) {
1897 QString file = dir[x];
1898 if(file == "." || file == "..") //blah
1899 continue;
1900 if(!uninst.isEmpty())
1901 uninst.append("\n\t");
1902 uninst.append(
1903#ifdef Q_WS_WIN
1904 QString("-$(DEL_FILE)")
1905#else
1906 QString("-$(DEL_FILE) -r")
1907#endif
1908 + " \"" + root + fileFixify(dst + file, QString::null, QString::null, FALSE, FALSE) +
1909 "\"");
1910 QFileInfo fi(Option::fixPathToTargetOS(fileFixify(dirstr + file), TRUE));
1911 if(!target.isEmpty())
1912 target += "\t";
1913 QString cmd = QString(fi.isDir() ? "-$(INSTALL_DIR)" : "-$(INSTALL_FILE)") + " \"" +
1914 Option::fixPathToTargetOS(fileFixify(dirstr + file, QString::null,
1915 QString::null, FALSE, FALSE), FALSE) +
1916 "\" \"" + root + fileFixify(dst) + "\"\n";
1917 target += cmd;
1918 if(!project->isActiveConfig("debug") &&
1919 !fi.isDir() && fi.isExecutable() && !project->isEmpty("QMAKE_STRIP"))
1920 target += QString("\t-") + var("QMAKE_STRIP") + " \"" +
1921 root + fileFixify(dst + file, QString::null, QString::null, FALSE, FALSE) +
1922 "\"\n";
1923 }
1924 }
1925 }
1926 //default?
1927 if(do_default) {
1928 target = defaultInstall((*it));
1929 uninst = project->variables()[(*it) + ".uninstall"];
1930 }
1931
1932 if(!target.isEmpty()) {
1933 t << "install_" << (*it) << ": all ";
1934 const QStringList &deps = project->variables()[(*it) + ".depends"];
1935 if(!deps.isEmpty()) {
1936 for(QStringList::ConstIterator dep_it = deps.begin(); dep_it != deps.end(); ++dep_it) {
1937 QString targ = var((*dep_it) + ".target");
1938 if(targ.isEmpty())
1939 targ = (*dep_it);
1940 t << targ;
1941 }
1942 }
1943 t << "\n\t";
1944 const QStringList &dirs = project->variables()[pvar];
1945 for(QStringList::ConstIterator pit = dirs.begin(); pit != dirs.end(); ++pit) {
1946 QString tmp_dst = fileFixify((*pit));
1947#ifndef Q_WS_WIN
1948 if(tmp_dst.right(1) != Option::dir_sep)
1949 tmp_dst += Option::dir_sep;
1950#endif
1951 t << mkdir_p_asstring(root+tmp_dst) << "\n\t";
1952 }
1953 t << target << endl << endl;
1954 if(!uninst.isEmpty()) {
1955 t << "uninstall_" << (*it) << ": " << "\n\t"
1956 << uninst.join("") << "\n\t"
1957 << "-$(DEL_DIR) \"" << ( root + dst ) << "\"" << endl << endl;
1958 }
1959 t << endl;
1960
1961 if(project->variables()[(*it) + ".CONFIG"].findIndex("no_default_install") == -1) {
1962 all_installs += QString("install_") + (*it) + " ";
1963 if(!uninst.isEmpty())
1964 all_uninstalls += "uninstall_" + (*it) + " ";
1965 }
1966 } else {
1967 debug_msg(1, "no definition for install %s: install target not created",(*it).latin1());
1968 }
1969 }
1970 t << "install: " << all_installs << " " << var("INSTALLDEPS") << "\n\n";
1971 t << "uninstall: " << all_uninstalls << " " << var("UNINSTALLDEPS") << "\n\n";
1972}
1973
1974QString
1975MakefileGenerator::var(const QString &var)
1976{
1977 return val(project->variables()[var]);
1978}
1979
1980QString
1981MakefileGenerator::val(const QStringList &varList)
1982{
1983 return valGlue(varList, "", " ", "");
1984}
1985
1986QString
1987MakefileGenerator::varGlue(const QString &var, const QString &before, const QString &glue, const QString &after)
1988{
1989 return valGlue(project->variables()[var], before, glue, after);
1990}
1991
1992QString
1993MakefileGenerator::valGlue(const QStringList &varList, const QString &before, const QString &glue, const QString &after)
1994{
1995 QString ret;
1996 for(QStringList::ConstIterator it = varList.begin(); it != varList.end(); ++it) {
1997 if(!(*it).isEmpty()) {
1998 if(!ret.isEmpty())
1999 ret += glue;
2000 ret += (*it);
2001 }
2002 }
2003 return ret.isEmpty() ? QString("") : before + ret + after;
2004}
2005
2006
2007QString
2008MakefileGenerator::varList(const QString &var)
2009{
2010 return valList(project->variables()[var]);
2011}
2012
2013QString
2014MakefileGenerator::valList(const QStringList &varList)
2015{
2016 return valGlue(varList, "", " \\\n\t\t", "");
2017}
2018
2019
2020QStringList
2021MakefileGenerator::createObjectList(const QString &var)
2022{
2023 QStringList &l = project->variables()[var], ret;
2024 QString objdir, dir;
2025 if(!project->variables()["OBJECTS_DIR"].isEmpty())
2026 objdir = project->first("OBJECTS_DIR");
2027 for(QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
2028 QFileInfo fi(Option::fixPathToLocalOS((*it)));
2029 if(objdir.isEmpty() && project->isActiveConfig("object_with_source")) {
2030 QString fName = Option::fixPathToTargetOS((*it), FALSE);
2031 int dl = fName.findRev(Option::dir_sep);
2032 if(dl != -1)
2033 dir = fName.left(dl + 1);
2034 } else {
2035 dir = objdir;
2036 }
2037 ret.append(dir + fi.baseName(TRUE) + Option::obj_ext);
2038 }
2039 return ret;
2040}
2041
2042bool
2043MakefileGenerator::writeMakefile(QTextStream &t)
2044{
2045 t << "####### Compile" << endl << endl;
2046 writeObj(t, "OBJECTS", "SOURCES");
2047 writeUicSrc(t, "FORMS");
2048 writeObj(t, "UICOBJECTS", "UICIMPLS");
2049 writeMocObj(t, "OBJMOC", "SRCMOC" );
2050 writeMocSrc(t, "HEADERS");
2051 writeMocSrc(t, "SOURCES");
2052 writeMocSrc(t, "UICDECLS");
2053 writeYaccSrc(t, "YACCSOURCES");
2054 writeLexSrc(t, "LEXSOURCES");
2055 writeImageObj(t, "IMAGEOBJECTS");
2056 writeImageSrc(t, "QMAKE_IMAGE_COLLECTION");
2057
2058 t << "####### Install" << endl << endl;
2059 writeInstalls(t, "INSTALLS");
2060 return TRUE;
2061}
2062
2063QString MakefileGenerator::buildArgs()
2064{
2065 static QString ret;
2066 if(ret.isEmpty()) {
2067 //special variables
2068 if(!project->isEmpty("QMAKE_ABSOLUTE_SOURCE_PATH"))
2069 ret += " QMAKE_ABSOLUTE_SOURCE_PATH=\"" + project->first("QMAKE_ABSOLUTE_SOURCE_PATH") + "\"";
2070
2071 //warnings
2072 else if(Option::warn_level == WarnNone)
2073 ret += " -Wnone";
2074 else if(Option::warn_level == WarnAll)
2075 ret += " -Wall";
2076 else if(Option::warn_level & WarnParser)
2077 ret += " -Wparser";
2078 //other options
2079 if(!Option::user_template.isEmpty())
2080 ret += " -t " + Option::user_template;
2081 if(!Option::mkfile::do_cache)
2082 ret += " -nocache";
2083 if(!Option::mkfile::do_deps)
2084 ret += " -nodepend";
2085 if(!Option::mkfile::do_mocs)
2086 ret += " -nomoc";
2087 if(!Option::mkfile::do_dep_heuristics)
2088 ret += " -nodependheuristics";
2089 if(!Option::mkfile::qmakespec_commandline.isEmpty())
2090 ret += " -spec " + Option::mkfile::qmakespec_commandline;
2091
2092 //arguments
2093 for(QStringList::Iterator it = Option::before_user_vars.begin();
2094 it != Option::before_user_vars.end(); ++it) {
2095 if((*it).left(qstrlen("QMAKE_ABSOLUTE_SOURCE_PATH")) != "QMAKE_ABSOLUTE_SOURCE_PATH")
2096 ret += " \"" + (*it) + "\"";
2097 }
2098 if(Option::after_user_vars.count()) {
2099 ret += " -after ";
2100 for(QStringList::Iterator it = Option::after_user_vars.begin();
2101 it != Option::after_user_vars.end(); ++it) {
2102 if((*it).left(qstrlen("QMAKE_ABSOLUTE_SOURCE_PATH")) != "QMAKE_ABSOLUTE_SOURCE_PATH")
2103 ret += " \"" + (*it) + "\"";
2104 }
2105 }
2106 }
2107 return ret;
2108}
2109
2110//could get stored argv, but then it would have more options than are
2111//probably necesary this will try to guess the bare minimum..
2112QString MakefileGenerator::build_args()
2113{
2114 static QString ret;
2115 if(ret.isEmpty()) {
2116 ret = "$(QMAKE)";
2117
2118 // general options and arguments
2119 ret += buildArgs();
2120
2121 //output
2122 QString ofile = Option::fixPathToTargetOS(fileFixify(Option::output.name()));
2123 if (!ofile.isEmpty() && ofile != project->first("QMAKE_MAKEFILE"))
2124 ret += " -o " + ofile;
2125
2126 //inputs
2127 QStringList files = fileFixify(Option::mkfile::project_files);
2128 ret += " " + files.join(" ");
2129 }
2130 return ret;
2131}
2132
2133bool
2134MakefileGenerator::writeHeader(QTextStream &t)
2135{
2136 time_t foo = time(NULL);
2137 t << "#############################################################################" << endl;
2138 t << "# Makefile for building: " << var("TARGET") << endl;
2139 t << "# Generated by qmake (" << qmake_version() << ") (Qt " << QT_VERSION_STR << ") on: " << ctime(&foo);
2140 t << "# Project: " << fileFixify(project->projectFile()) << endl;
2141 t << "# Template: " << var("TEMPLATE") << endl;
2142 t << "# Command: " << build_args() << endl;
2143 t << "#############################################################################" << endl;
2144 t << endl;
2145 return TRUE;
2146}
2147
2148
2149//makes my life easier..
2150bool
2151MakefileGenerator::writeMakeQmake(QTextStream &t)
2152{
2153 QString ofile = Option::fixPathToTargetOS(fileFixify(Option::output.name()));
2154 if(project->isEmpty("QMAKE_FAILED_REQUIREMENTS") && !project->isActiveConfig("no_autoqmake") &&
2155 !project->isEmpty("QMAKE_INTERNAL_PRL_FILE")) {
2156 QStringList files = fileFixify(Option::mkfile::project_files);
2157 t << project->first("QMAKE_INTERNAL_PRL_FILE") << ": " << "\n\t"
2158 << "@$(QMAKE) -prl " << buildArgs() << " " << files.join(" ") << endl;
2159 }
2160
2161 QString pfile = project->projectFile();
2162 if(pfile != "(stdin)") {
2163 QString qmake = build_args();
2164 if(!ofile.isEmpty() && !project->isActiveConfig("no_autoqmake")) {
2165 t << ofile << ": " << fileFixify(pfile) << " ";
2166 if(Option::mkfile::do_cache)
2167 t << fileFixify(Option::mkfile::cachefile) << " ";
2168 if(!specdir().isEmpty()) {
2169 if (QFile::exists(Option::fixPathToLocalOS(specdir()+QDir::separator()+"qmake.conf")))
2170 t << specdir() << Option::dir_sep << "qmake.conf" << " ";
2171 else if (QFile::exists(Option::fixPathToLocalOS(specdir()+QDir::separator()+"tmake.conf")))
2172 t << specdir() << Option::dir_sep << "tmake.conf" << " ";
2173 }
2174 t << project->variables()["QMAKE_INTERNAL_INCLUDED_FILES"].join(" \\\n\t\t") << "\n\t"
2175 << qmake <<endl;
2176 }
2177 if(project->first("QMAKE_ORIG_TARGET") != "qmake") {
2178 t << "qmake: " <<
2179 project->variables()["QMAKE_INTERNAL_QMAKE_DEPS"].join(" \\\n\t\t") << "\n\t"
2180 << "@" << qmake << endl << endl;
2181 }
2182 }
2183 return TRUE;
2184}
2185
2186QStringList
2187MakefileGenerator::fileFixify(const QStringList& files, const QString &out_dir, const QString &in_dir,
2188 bool force_fix, bool canon) const
2189{
2190 if(files.isEmpty())
2191 return files;
2192 QStringList ret;
2193 for(QStringList::ConstIterator it = files.begin(); it != files.end(); ++it) {
2194 if(!(*it).isEmpty())
2195 ret << fileFixify((*it), out_dir, in_dir, force_fix, canon);
2196 }
2197 return ret;
2198}
2199
2200QString
2201MakefileGenerator::fileFixify(const QString& file0, const QString &out_d,
2202 const QString &in_d, bool force_fix, bool canon) const
2203{
2204 if(file0.isEmpty())
2205 return file0;
2206 QString key = file0;
2207 if(QDir::isRelativePath(file0))
2208 key.prepend(QDir::currentDirPath() + "--");
2209 if(!in_d.isEmpty() || !out_d.isEmpty() || force_fix || !canon)
2210 key.prepend(in_d + "--" + out_d + "--" + QString::number((int)force_fix) + "--" +
2211 QString::number((int)canon) + "-");
2212 if(fileFixed.contains(key))
2213 return fileFixed[key];
2214
2215 QString file = file0;
2216 int depth = 4;
2217 if(Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE ||
2218 Option::qmake_mode == Option::QMAKE_GENERATE_PRL) {
2219 if(project && !project->isEmpty("QMAKE_PROJECT_DEPTH"))
2220 depth = project->first("QMAKE_PROJECT_DEPTH").toInt();
2221 else if(Option::mkfile::cachefile_depth != -1)
2222 depth = Option::mkfile::cachefile_depth;
2223 }
2224
2225 QChar quote;
2226 if((file.startsWith("'") || file.startsWith("\"")) && file.startsWith(file.right(1))) {
2227 quote = file.at(0);
2228 file = file.mid(1, file.length() - 2);
2229 }
2230 QString orig_file = file;
2231 if(!force_fix && project->isActiveConfig("no_fixpath")) {
2232 if(!project->isEmpty("QMAKE_ABSOLUTE_SOURCE_PATH")) { //absoluteify it
2233 QString qfile = Option::fixPathToLocalOS(file, TRUE, canon);
2234 if(QDir::isRelativePath(file)) { //already absolute
2235 QFileInfo fi(qfile);
2236 if(!fi.convertToAbs()) //strange
2237 file = fi.filePath();
2238 }
2239 }
2240 } else { //fix it..
2241 QString qfile(Option::fixPathToLocalOS(file, TRUE, canon)), in_dir(in_d), out_dir(out_d);
2242 {
2243 if(out_dir.isNull() || QDir::isRelativePath(out_dir))
2244 out_dir.prepend(Option::output_dir + QDir::separator());
2245 if(out_dir == ".")
2246 out_dir = QDir::currentDirPath();
2247 if(in_dir.isEmpty() || QDir::isRelativePath(in_dir))
2248 in_dir.prepend(QDir::currentDirPath() + QDir::separator());
2249 if(in_dir == ".")
2250 in_dir = QDir::currentDirPath();
2251
2252 if(!QDir::isRelativePath(in_dir) || !QDir::isRelativePath(out_dir)) {
2253 QFileInfo in_fi(in_dir);
2254 if(!in_fi.convertToAbs())
2255 in_dir = in_fi.filePath();
2256 QFileInfo out_fi(out_dir);
2257 if(!out_fi.convertToAbs())
2258 out_dir = out_fi.filePath();
2259 }
2260 QString in_canonical_dir = QDir(in_dir).canonicalPath(),
2261 out_canonical_dir = QDir(out_dir).canonicalPath();
2262 if(!in_canonical_dir.isEmpty())
2263 in_dir = in_canonical_dir;
2264 if(!out_canonical_dir.isEmpty())
2265 out_dir = out_canonical_dir;
2266 }
2267 if(out_dir != in_dir || !QDir::isRelativePath(qfile)) {
2268 if(QDir::isRelativePath(qfile)) {
2269 if(file.left(Option::dir_sep.length()) != Option::dir_sep &&
2270 in_dir.right(Option::dir_sep.length()) != Option::dir_sep)
2271 file.prepend(Option::dir_sep);
2272 file.prepend(in_dir);
2273 }
2274 file = Option::fixPathToTargetOS(file, FALSE, canon);
2275 if(canon && QFile::exists(file) && file == Option::fixPathToTargetOS(file, TRUE, canon)) {
2276 QString real_file = QDir(file).canonicalPath();
2277 if(!real_file.isEmpty())
2278 file = real_file;
2279 }
2280 QString match_dir = Option::fixPathToTargetOS(out_dir, FALSE, canon);
2281 if(file == match_dir) {
2282 file = "";
2283 } else if(file.startsWith(match_dir) &&
2284 file.mid(match_dir.length(), Option::dir_sep.length()) == Option::dir_sep) {
2285 file = file.right(file.length() - (match_dir.length() + 1));
2286 } else {
2287 for(int i = 1; i <= depth; i++) {
2288 int sl = match_dir.findRev(Option::dir_sep);
2289 if(sl == -1)
2290 break;
2291 match_dir = match_dir.left(sl);
2292 if(match_dir.isEmpty())
2293 break;
2294 if(file.startsWith(match_dir) &&
2295 file.mid(match_dir.length(), Option::dir_sep.length()) == Option::dir_sep) {
2296 //concat
2297 int remlen = file.length() - (match_dir.length() + 1);
2298 if (remlen < 0)
2299 remlen = 0;
2300 file = file.right(remlen);
2301 //prepend
2302 for(int o = 0; o < i; o++)
2303 file.prepend(".." + Option::dir_sep);
2304 }
2305 }
2306 }
2307 }
2308 }
2309 file = Option::fixPathToTargetOS(file, FALSE, canon);
2310 if(file.isEmpty())
2311 file = ".";
2312 if(!quote.isNull())
2313 file = quote + file + quote;
2314 debug_msg(3, "Fixed %s :: to :: %s (%d) [%s::%s]", orig_file.latin1(), file.latin1(), depth,
2315 in_d.latin1(), out_d.latin1());
2316 ((MakefileGenerator*)this)->fileFixed.insert(key, file);
2317 return file;
2318}
2319
2320QString
2321MakefileGenerator::cleanFilePath(const QString &file) const
2322{
2323 return fileFixify(Option::fixPathToTargetOS(file));
2324}
2325
2326void MakefileGenerator::logicWarn(const QString &f, const QString &w)
2327{
2328 if(!(Option::warn_level & WarnLogic))
2329 return;
2330 QString file = f;
2331 int slsh = f.findRev(Option::dir_sep);
2332 if(slsh != -1)
2333 file = file.right(file.length() - slsh - 1);
2334 QStringList &l = project->variables()[w];
2335 for(QStringList::Iterator val_it = l.begin(); val_it != l.end(); ++val_it) {
2336 QString file2((*val_it));
2337 slsh = file2.findRev(Option::dir_sep);
2338 if(slsh != -1)
2339 file2 = file2.right(file2.length() - slsh - 1);
2340 if(file2 == file) {
2341 warn_msg(WarnLogic, "Found potential symbol conflict of %s (%s) in %s",
2342 file.latin1(), (*val_it).latin1(), w.latin1());
2343 break;
2344 }
2345 }
2346}
2347
2348QString
2349MakefileGenerator::dependencyKey(const QString &file) const
2350{
2351 QString key = file;
2352 Option::fixPathToTargetOS(key);
2353 if(key.find(Option::dir_sep))
2354 key = key.right(key.length() - key.findRev(Option::dir_sep) - 1);
2355 return key;
2356}
2357
2358void
2359MakefileGenerator::setProcessedDependencies(const QString &file, bool b)
2360{
2361 depProcessed[dependencyKey(file)] = b;
2362}
2363
2364bool
2365MakefileGenerator::processedDependencies(const QString &file)
2366{
2367 QString key = dependencyKey(file);
2368 if(!depProcessed.contains(key))
2369 return FALSE;
2370 return depProcessed[key];
2371}
2372
2373QStringList
2374&MakefileGenerator::findDependencies(const QString &file)
2375{
2376 return depends[dependencyKey(file)];
2377}
2378
2379
2380QString
2381MakefileGenerator::specdir()
2382{
2383 if(!spec.isEmpty())
2384 return spec;
2385 spec = Option::mkfile::qmakespec;
2386#if 0
2387 if(const char *d = getenv("QTDIR")) {
2388 QString qdir = Option::fixPathToTargetOS(QString(d));
2389 if(qdir.endsWith(QString(QChar(QDir::separator()))))
2390 qdir.truncate(qdir.length()-1);
2391 //fix path
2392 QFileInfo fi(spec);
2393 QString absSpec(fi.absFilePath());
2394 absSpec = Option::fixPathToTargetOS(absSpec);
2395 //replace what you can
2396 if(absSpec.startsWith(qdir)) {
2397 absSpec.replace(0, qdir.length(), "$(QTDIR)");
2398 spec = absSpec;
2399 }
2400 }
2401#else
2402 spec = Option::fixPathToTargetOS(spec);
2403#endif
2404 return spec;
2405}
2406
2407bool
2408MakefileGenerator::openOutput(QFile &file) const
2409{
2410 {
2411 QString outdir;
2412 if(!file.name().isEmpty()) {
2413 if(QDir::isRelativePath(file.name()))
2414 file.setName(Option::output_dir + file.name()); //pwd when qmake was run
2415 QFileInfo fi(file);
2416 if(fi.isDir())
2417 outdir = file.name() + QDir::separator();
2418 }
2419 if(!outdir.isEmpty() || file.name().isEmpty()) {
2420 QString fname = "Makefile";
2421 if(!project->isEmpty("MAKEFILE"))
2422 fname = project->first("MAKEFILE");
2423 file.setName(outdir + fname);
2424 }
2425 }
2426 if(QDir::isRelativePath(file.name()))
2427 file.setName(Option::output_dir + file.name()); //pwd when qmake was run
2428 if(project->isEmpty("QMAKE_MAKEFILE"))
2429 project->variables()["QMAKE_MAKEFILE"].append(file.name());
2430 int slsh = file.name().findRev(Option::dir_sep);
2431 if(slsh != -1)
2432 createDir(file.name().left(slsh));
2433 if(file.open(IO_WriteOnly | IO_Translate)) {
2434 QFileInfo fi(Option::output);
2435 QString od = Option::fixPathToTargetOS((fi.isSymLink() ? fi.readLink() : fi.dirPath()) );
2436 if(QDir::isRelativePath(od))
2437 od.prepend(Option::output_dir);
2438 Option::output_dir = od;
2439 return TRUE;
2440 }
2441 return FALSE;
2442}
2443
2444
2445
2446//Factory thing
2447#include "unixmake.h"
2448#include "msvc_nmake.h"
2449#include "borland_bmake.h"
2450#include "mingw_make.h"
2451#include "msvc_dsp.h"
2452#include "msvc_vcproj.h"
2453#include "metrowerks_xml.h"
2454#include "pbuilder_pbx.h"
2455#include "projectgenerator.h"
2456
2457MakefileGenerator *
2458MakefileGenerator::create(QMakeProject *proj)
2459{
2460 if(Option::qmake_mode == Option::QMAKE_GENERATE_PROJECT)
2461 return new ProjectGenerator(proj);
2462
2463 MakefileGenerator *mkfile = NULL;
2464 QString gen = proj->first("MAKEFILE_GENERATOR");
2465 if(gen.isEmpty()) {
2466 fprintf(stderr, "No generator specified in config file: %s\n",
2467 proj->projectFile().latin1());
2468 } else if(gen == "UNIX") {
2469 mkfile = new UnixMakefileGenerator(proj);
2470 } else if(gen == "MSVC") {
2471 // Visual Studio =< v6.0
2472 if(proj->first("TEMPLATE").find(QRegExp("^vc.*")) != -1)
2473 mkfile = new DspMakefileGenerator(proj);
2474 else
2475 mkfile = new NmakeMakefileGenerator(proj);
2476 } else if(gen == "MSVC.NET") {
2477 // Visual Studio >= v7.0
2478 if(proj->first("TEMPLATE").find(QRegExp("^vc.*")) != -1)
2479 mkfile = new VcprojGenerator(proj);
2480 else
2481 mkfile = new NmakeMakefileGenerator(proj);
2482 } else if(gen == "BMAKE") {
2483 mkfile = new BorlandMakefileGenerator(proj);
2484 } else if(gen == "MINGW") {
2485 mkfile = new MingwMakefileGenerator(proj);
2486 } else if(gen == "METROWERKS") {
2487 mkfile = new MetrowerksMakefileGenerator(proj);
2488 } else if(gen == "PROJECTBUILDER") {
2489 mkfile = new ProjectBuilderMakefileGenerator(proj);
2490 } else {
2491 fprintf(stderr, "Unknown generator specified: %s\n", gen.latin1());
2492 }
2493 return mkfile;
2494}
Note: See TracBrowser for help on using the repository browser.