Warning: That file was not part of the compilation database. It may have many parsing errors.
1 | /**************************************************************************** |
---|---|
2 | ** |
3 | ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). |
4 | ** Contact: http://www.qt-project.org/legal |
5 | ** |
6 | ** This file is part of the qmake application of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and Digia. For licensing terms and |
14 | ** conditions see http://qt.digia.com/licensing. For further information |
15 | ** use the contact form at http://qt.digia.com/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 2.1 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 2.1 requirements |
23 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
24 | ** |
25 | ** In addition, as a special exception, Digia gives you certain additional |
26 | ** rights. These rights are described in the Digia Qt LGPL Exception |
27 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
28 | ** |
29 | ** GNU General Public License Usage |
30 | ** Alternatively, this file may be used under the terms of the GNU |
31 | ** General Public License version 3.0 as published by the Free Software |
32 | ** Foundation and appearing in the file LICENSE.GPL included in the |
33 | ** packaging of this file. Please review the following information to |
34 | ** ensure the GNU General Public License version 3.0 requirements will be |
35 | ** met: http://www.gnu.org/copyleft/gpl.html. |
36 | ** |
37 | ** |
38 | ** $QT_END_LICENSE$ |
39 | ** |
40 | ****************************************************************************/ |
41 | |
42 | #include "makefile.h" |
43 | #include "option.h" |
44 | #include "cachekeys.h" |
45 | #include "meta.h" |
46 | #include <qdir.h> |
47 | #include <qfile.h> |
48 | #include <qtextstream.h> |
49 | #include <qregexp.h> |
50 | #include <qhash.h> |
51 | #include <qdebug.h> |
52 | #include <qbuffer.h> |
53 | #include <qsettings.h> |
54 | #include <qdatetime.h> |
55 | #if defined(Q_OS_UNIX) |
56 | #include <unistd.h> |
57 | #else |
58 | #include <io.h> |
59 | #endif |
60 | #include <qdebug.h> |
61 | #include <stdio.h> |
62 | #include <stdlib.h> |
63 | #include <time.h> |
64 | #include <fcntl.h> |
65 | #include <sys/types.h> |
66 | #include <sys/stat.h> |
67 | |
68 | QT_BEGIN_NAMESPACE |
69 | |
70 | // Well, Windows doesn't have this, so here's the macro |
71 | #ifndef S_ISDIR |
72 | # define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) |
73 | #endif |
74 | |
75 | bool MakefileGenerator::canExecute(const QStringList &cmdline, int *a) const |
76 | { |
77 | int argv0 = -1; |
78 | for(int i = 0; i < cmdline.count(); ++i) { |
79 | if(!cmdline.at(i).contains( |
80 | argv0 = i; |
81 | break; |
82 | } |
83 | } |
84 | if(a) |
85 | *a = argv0; |
86 | if(argv0 != -1) { |
87 | const QString c = Option::fixPathToLocalOS(cmdline.at(argv0), true); |
88 | if(exists(c)) |
89 | return true; |
90 | } |
91 | return false; |
92 | } |
93 | |
94 | QString MakefileGenerator::mkdir_p_asstring(const QString &dir, bool escape) const |
95 | { |
96 | QString ret = "@$(CHK_DIR_EXISTS) "; |
97 | if(escape) |
98 | ret += escapeFilePath(dir); |
99 | else |
100 | ret += dir; |
101 | ret += " "; |
102 | if(isWindowsShell()) |
103 | ret += "$(MKDIR)"; |
104 | else |
105 | ret += "|| $(MKDIR)"; |
106 | ret += " "; |
107 | if(escape) |
108 | ret += escapeFilePath(dir); |
109 | else |
110 | ret += dir; |
111 | ret += " "; |
112 | return ret; |
113 | } |
114 | |
115 | bool MakefileGenerator::mkdir(const QString &in_path) const |
116 | { |
117 | QString path = Option::fixPathToLocalOS(in_path); |
118 | if(QFile::exists(path)) |
119 | return true; |
120 | |
121 | QDir d; |
122 | if(path.startsWith(QDir::separator())) { |
123 | d.cd(QString(QDir::separator())); |
124 | path.remove(0, 1); |
125 | } |
126 | bool ret = true; |
127 | #ifdef Q_OS_WIN |
128 | bool driveExists = true; |
129 | if(!QDir::isRelativePath(path)) { |
130 | if(QFile::exists(path.left(3))) { |
131 | d.cd(path.left(3)); |
132 | path.remove(0, 3); |
133 | } else { |
134 | warn_msg(WarnLogic, "Cannot access drive '%s' (%s)", |
135 | path.left(3).toLatin1().data(), path.toLatin1().data()); |
136 | driveExists = false; |
137 | } |
138 | } |
139 | if(driveExists) |
140 | #endif |
141 | { |
142 | QStringList subs = path.split(QDir::separator()); |
143 | for(QStringList::Iterator subit = subs.begin(); subit != subs.end(); ++subit) { |
144 | if(!d.cd(*subit)) { |
145 | d.mkdir((*subit)); |
146 | if(d.exists((*subit))) { |
147 | d.cd((*subit)); |
148 | } else { |
149 | ret = false; |
150 | break; |
151 | } |
152 | } |
153 | } |
154 | } |
155 | return ret; |
156 | } |
157 | |
158 | // ** base makefile generator |
159 | MakefileGenerator::MakefileGenerator() : |
160 | init_opath_already(false), init_already(false), no_io(false), project(0) |
161 | { |
162 | } |
163 | |
164 | |
165 | void |
166 | MakefileGenerator::verifyCompilers() |
167 | { |
168 | QMap<QString, QStringList> &v = project->variables(); |
169 | QStringList &quc = v["QMAKE_EXTRA_COMPILERS"]; |
170 | for(int i = 0; i < quc.size(); ) { |
171 | bool error = false; |
172 | QString comp = quc.at(i); |
173 | if(v[comp + ".output"].isEmpty()) { |
174 | if(!v[comp + ".output_function"].isEmpty()) { |
175 | v[comp + ".output"].append( "${QMAKE_FUNC_FILE_IN_"+ v[comp + ".output_function"].first() + "}"); |
176 | } else { |
177 | error = true; |
178 | warn_msg(WarnLogic, "Compiler: %s: No output file specified", comp.toLatin1().constData()); |
179 | } |
180 | } else if(v[comp + ".input"].isEmpty()) { |
181 | error = true; |
182 | warn_msg(WarnLogic, "Compiler: %s: No input variable specified", comp.toLatin1().constData()); |
183 | } |
184 | if(error) |
185 | quc.removeAt(i); |
186 | else |
187 | ++i; |
188 | } |
189 | } |
190 | |
191 | void |
192 | MakefileGenerator::initOutPaths() |
193 | { |
194 | if(init_opath_already) |
195 | return; |
196 | verifyCompilers(); |
197 | init_opath_already = true; |
198 | QMap<QString, QStringList> &v = project->variables(); |
199 | //for shadow builds |
200 | if(!v.contains("QMAKE_ABSOLUTE_SOURCE_PATH")) { |
201 | if(Option::mkfile::do_cache && !Option::mkfile::cachefile.isEmpty() && |
202 | v.contains("QMAKE_ABSOLUTE_SOURCE_ROOT")) { |
203 | QString root = v["QMAKE_ABSOLUTE_SOURCE_ROOT"].first(); |
204 | root = QDir::fromNativeSeparators(root); |
205 | if(!root.isEmpty()) { |
206 | QFileInfo fi = fileInfo(Option::mkfile::cachefile); |
207 | if(!fi.makeAbsolute()) { |
208 | QString cache_r = fi.path(), pwd = Option::output_dir; |
209 | if(pwd.startsWith(cache_r) && !pwd.startsWith(root)) { |
210 | pwd = root + pwd.mid(cache_r.length()); |
211 | if(exists(pwd)) |
212 | v.insert("QMAKE_ABSOLUTE_SOURCE_PATH", QStringList(pwd)); |
213 | } |
214 | } |
215 | } |
216 | } |
217 | } |
218 | if(!v["QMAKE_ABSOLUTE_SOURCE_PATH"].isEmpty()) { |
219 | QString &asp = v["QMAKE_ABSOLUTE_SOURCE_PATH"].first(); |
220 | asp = QDir::fromNativeSeparators(asp); |
221 | if(asp.isEmpty() || asp == Option::output_dir) //if they're the same, why bother? |
222 | v["QMAKE_ABSOLUTE_SOURCE_PATH"].clear(); |
223 | } |
224 | |
225 | QString currentDir = qmake_getpwd(); //just to go back to |
226 | |
227 | //some builtin directories |
228 | if(project->isEmpty("PRECOMPILED_DIR") && !project->isEmpty( "OBJECTS_DIR")) |
229 | v["PRECOMPILED_DIR"] = v[ "OBJECTS_DIR"]; |
230 | QString dirs[] = { QString("OBJECTS_DIR"), QString( "DESTDIR"), QString( "QMAKE_PKGCONFIG_DESTDIR"), |
231 | QString("SUBLIBS_DIR"), QString( "DLLDESTDIR"), QString( "QMAKE_LIBTOOL_DESTDIR"), |
232 | QString("PRECOMPILED_DIR"), QString() }; |
233 | for(int x = 0; !dirs[x].isEmpty(); x++) { |
234 | if(v[dirs[x]].isEmpty()) |
235 | continue; |
236 | const QString orig_path = v[dirs[x]].first(); |
237 | |
238 | QString &pathRef = v[dirs[x]].first(); |
239 | pathRef = fileFixify(pathRef, Option::output_dir, Option::output_dir); |
240 | |
241 | #ifdef Q_OS_WIN |
242 | // We don't want to add a separator for DLLDESTDIR on Windows (###why?) |
243 | if(!(dirs[x] == "DLLDESTDIR")) |
244 | #endif |
245 | { |
246 | if(!pathRef.endsWith(Option::dir_sep)) |
247 | pathRef += Option::dir_sep; |
248 | } |
249 | |
250 | if(noIO()) |
251 | continue; |
252 | |
253 | QString path = project->first(dirs[x]); //not to be changed any further |
254 | path = fileFixify(path, currentDir, Option::output_dir); |
255 | debug_msg(3, "Fixed output_dir %s (%s) into %s", dirs[x].toLatin1().constData(), |
256 | orig_path.toLatin1().constData(), path.toLatin1().constData()); |
257 | if(!mkdir(path)) |
258 | warn_msg(WarnLogic, "%s: Cannot access directory '%s'", dirs[x].toLatin1().constData(), |
259 | path.toLatin1().constData()); |
260 | } |
261 | |
262 | //out paths from the extra compilers |
263 | const QStringList &quc = project->values("QMAKE_EXTRA_COMPILERS"); |
264 | for(QStringList::ConstIterator it = quc.begin(); it != quc.end(); ++it) { |
265 | QString tmp_out = project->values((*it) + ".output").first(); |
266 | if(tmp_out.isEmpty()) |
267 | continue; |
268 | const QStringList &tmp = project->values((*it) + ".input"); |
269 | for(QStringList::ConstIterator it2 = tmp.begin(); it2 != tmp.end(); ++it2) { |
270 | QStringList &inputs = project->values((*it2)); |
271 | for(QStringList::Iterator input = inputs.begin(); input != inputs.end(); ++input) { |
272 | (*input) = fileFixify((*input), Option::output_dir, Option::output_dir); |
273 | QString path = unescapeFilePath(replaceExtraCompilerVariables(tmp_out, (*input), QString())); |
274 | path = Option::fixPathToTargetOS(path); |
275 | int slash = path.lastIndexOf(Option::dir_sep); |
276 | if(slash != -1) { |
277 | path = path.left(slash); |
278 | // Make out path only if it does not contain makefile variables |
279 | if(!path.contains("${")) |
280 | if(path != "."&& |
281 | !mkdir(fileFixify(path, qmake_getpwd(), Option::output_dir))) |
282 | warn_msg(WarnLogic, "%s: Cannot access directory '%s'", |
283 | (*it).toLatin1().constData(), path.toLatin1().constData()); |
284 | } |
285 | } |
286 | } |
287 | } |
288 | |
289 | if(!v["DESTDIR"].isEmpty()) { |
290 | QDir d(v["DESTDIR"].first()); |
291 | if(Option::fixPathToLocalOS(d.absolutePath()) == Option::fixPathToLocalOS(Option::output_dir)) |
292 | v.remove("DESTDIR"); |
293 | } |
294 | } |
295 | |
296 | QMakeProject |
297 | *MakefileGenerator::projectFile() const |
298 | { |
299 | return project; |
300 | } |
301 | |
302 | void |
303 | MakefileGenerator::setProjectFile(QMakeProject *p) |
304 | { |
305 | if(project) |
306 | return; |
307 | project = p; |
308 | init(); |
309 | usePlatformDir(); |
310 | findLibraries(); |
311 | if(Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE && |
312 | project->isActiveConfig("link_prl")) //load up prl's' |
313 | processPrlFiles(); |
314 | } |
315 | |
316 | QStringList |
317 | MakefileGenerator::findFilesInVPATH(QStringList l, uchar flags, const QString &vpath_var) |
318 | { |
319 | QStringList vpath; |
320 | QMap<QString, QStringList> &v = project->variables(); |
321 | for(int val_it = 0; val_it < l.count(); ) { |
322 | bool remove_file = false; |
323 | QString &val = l[val_it]; |
324 | if(!val.isEmpty()) { |
325 | QString file = fixEnvVariables(val); |
326 | if(!(flags & VPATH_NoFixify)) |
327 | file = fileFixify(file, qmake_getpwd(), Option::output_dir); |
328 | if (file.at(0) == |
329 | file = file.mid(1, file.length() - 2); |
330 | |
331 | if(exists(file)) { |
332 | ++val_it; |
333 | continue; |
334 | } |
335 | bool found = false; |
336 | if(QDir::isRelativePath(val)) { |
337 | if(vpath.isEmpty()) { |
338 | if(!vpath_var.isEmpty()) |
339 | vpath = v[vpath_var]; |
340 | vpath += v["VPATH"] + v[ "QMAKE_ABSOLUTE_SOURCE_PATH"] + v[ "DEPENDPATH"]; |
341 | if(Option::output_dir != qmake_getpwd()) |
342 | vpath += Option::output_dir; |
343 | } |
344 | for(QStringList::Iterator vpath_it = vpath.begin(); |
345 | vpath_it != vpath.end(); ++vpath_it) { |
346 | QString real_dir = Option::fixPathToLocalOS((*vpath_it)); |
347 | if(exists(real_dir + QDir::separator() + val)) { |
348 | QString dir = (*vpath_it); |
349 | if(!dir.endsWith(Option::dir_sep)) |
350 | dir += Option::dir_sep; |
351 | val = dir + val; |
352 | if(!(flags & VPATH_NoFixify)) |
353 | val = fileFixify(val); |
354 | found = true; |
355 | debug_msg(1, "Found file through vpath %s -> %s", |
356 | file.toLatin1().constData(), val.toLatin1().constData()); |
357 | break; |
358 | } |
359 | } |
360 | } |
361 | if(!found) { |
362 | QString dir, regex = val, real_dir; |
363 | if(regex.lastIndexOf(Option::dir_sep) != -1) { |
364 | dir = regex.left(regex.lastIndexOf(Option::dir_sep) + 1); |
365 | real_dir = dir; |
366 | if(!(flags & VPATH_NoFixify)) |
367 | real_dir = fileFixify(real_dir, qmake_getpwd(), Option::output_dir) + |
368 | regex.remove(0, dir.length()); |
369 | } |
370 | if(real_dir.isEmpty() || exists(real_dir)) { |
371 | QStringList files = QDir(real_dir).entryList(QStringList(regex)); |
372 | if(files.isEmpty()) { |
373 | debug_msg(1, "%s:%d Failure to find %s in vpath (%s)", |
374 | __FILE__, __LINE__, |
375 | val.toLatin1().constData(), vpath.join("::").toLatin1().constData()); |
376 | if(flags & VPATH_RemoveMissingFiles) |
377 | remove_file = true; |
378 | else if(flags & VPATH_WarnMissingFiles) |
379 | warn_msg(WarnLogic, "Failure to find: %s", val.toLatin1().constData()); |
380 | } else { |
381 | l.removeAt(val_it); |
382 | QString a; |
383 | for(int i = (int)files.count()-1; i >= 0; i--) { |
384 | if(files[i] == "."|| files[i] == "..") |
385 | continue; |
386 | a = real_dir + files[i]; |
387 | if(!(flags & VPATH_NoFixify)) |
388 | a = fileFixify(a); |
389 | l.insert(val_it, a); |
390 | } |
391 | } |
392 | } else { |
393 | debug_msg(1, "%s:%d Cannot match %s%s, as %s does not exist.", |
394 | __FILE__, __LINE__, real_dir.toLatin1().constData(), |
395 | regex.toLatin1().constData(), real_dir.toLatin1().constData()); |
396 | if(flags & VPATH_RemoveMissingFiles) |
397 | remove_file = true; |
398 | else if(flags & VPATH_WarnMissingFiles) |
399 | warn_msg(WarnLogic, "Failure to find: %s", val.toLatin1().constData()); |
400 | } |
401 | } |
402 | } |
403 | if(remove_file) |
404 | l.removeAt(val_it); |
405 | else |
406 | ++val_it; |
407 | } |
408 | return l; |
409 | } |
410 | |
411 | void |
412 | MakefileGenerator::initCompiler(const MakefileGenerator::Compiler &comp) |
413 | { |
414 | QMap<QString, QStringList> &v = project->variables(); |
415 | QStringList &l = v[comp.variable_in]; |
416 | // find all the relevant file inputs |
417 | if(!init_compiler_already.contains(comp.variable_in)) { |
418 | init_compiler_already.insert(comp.variable_in, true); |
419 | if(!noIO()) |
420 | l = findFilesInVPATH(l, (comp.flags & Compiler::CompilerRemoveNoExist) ? |
421 | VPATH_RemoveMissingFiles : VPATH_WarnMissingFiles, "VPATH_"+ comp.variable_in); |
422 | } |
423 | } |
424 | |
425 | void |
426 | MakefileGenerator::init() |
427 | { |
428 | initOutPaths(); |
429 | if(init_already) |
430 | return; |
431 | verifyCompilers(); |
432 | init_already = true; |
433 | |
434 | QMap<QString, QStringList> &v = project->variables(); |
435 | QStringList &quc = v["QMAKE_EXTRA_COMPILERS"]; |
436 | |
437 | //make sure the COMPILERS are in the correct input/output chain order |
438 | for(int comp_out = 0, jump_count = 0; comp_out < quc.size(); ++comp_out) { |
439 | continue_compiler_chain: |
440 | if(jump_count > quc.size()) //just to avoid an infinite loop here |
441 | break; |
442 | if(project->variables().contains(quc.at(comp_out) + ".variable_out")) { |
443 | const QStringList &outputs = project->variables().value(quc.at(comp_out) + ".variable_out"); |
444 | for(int out = 0; out < outputs.size(); ++out) { |
445 | for(int comp_in = 0; comp_in < quc.size(); ++comp_in) { |
446 | if(comp_in == comp_out) |
447 | continue; |
448 | if(project->variables().contains(quc.at(comp_in) + ".input")) { |
449 | const QStringList &inputs = project->variables().value(quc.at(comp_in) + ".input"); |
450 | for(int in = 0; in < inputs.size(); ++in) { |
451 | if(inputs.at(in) == outputs.at(out) && comp_out > comp_in) { |
452 | ++jump_count; |
453 | //move comp_out to comp_in and continue the compiler chain |
454 | quc.move(comp_out, comp_in); |
455 | comp_out = comp_in; |
456 | goto continue_compiler_chain; |
457 | } |
458 | } |
459 | } |
460 | } |
461 | } |
462 | } |
463 | } |
464 | |
465 | if(!project->isEmpty("QMAKE_SUBSTITUTES")) { |
466 | const QStringList &subs = v["QMAKE_SUBSTITUTES"]; |
467 | for(int i = 0; i < subs.size(); ++i) { |
468 | QString inn = subs.at(i) + ".input", outn = subs.at(i) + ".output"; |
469 | if (v.contains(inn) || v.contains(outn)) { |
470 | if (!v.contains(inn) || !v.contains(outn)) { |
471 | warn_msg(WarnLogic, "Substitute '%s' has only one of .input and .output", |
472 | subs.at(i).toLatin1().constData()); |
473 | continue; |
474 | } |
475 | const QStringList &tinn = v[inn], &toutn = v[outn]; |
476 | if (tinn.length() != 1) { |
477 | warn_msg(WarnLogic, "Substitute '%s.input' does not have exactly one value", |
478 | subs.at(i).toLatin1().constData()); |
479 | continue; |
480 | } |
481 | if (toutn.length() != 1) { |
482 | warn_msg(WarnLogic, "Substitute '%s.output' does not have exactly one value", |
483 | subs.at(i).toLatin1().constData()); |
484 | continue; |
485 | } |
486 | inn = fileFixify(tinn.first(), qmake_getpwd()); |
487 | outn = fileFixify(toutn.first(), qmake_getpwd(), Option::output_dir); |
488 | } else { |
489 | inn = fileFixify(subs.at(i), qmake_getpwd()); |
490 | if (!QFile::exists(inn)) { |
491 | // random insanity for backwards compat: .in file specified with absolute out dir |
492 | inn = fileFixify(subs.at(i)); |
493 | } |
494 | if(!inn.endsWith(".in")) { |
495 | warn_msg(WarnLogic, "Substitute '%s' does not end with '.in'", |
496 | inn.toLatin1().constData()); |
497 | continue; |
498 | } |
499 | outn = fileFixify(inn.left(inn.length()-3), qmake_getpwd(), Option::output_dir); |
500 | } |
501 | QFile in(inn); |
502 | if(in.open(QFile::ReadOnly)) { |
503 | QString contents; |
504 | QStack<int> state; |
505 | enum { IN_CONDITION, MET_CONDITION, PENDING_CONDITION }; |
506 | for(int count = 1; !in.atEnd(); ++count) { |
507 | QString line = QString::fromUtf8(in.readLine()); |
508 | if(line.startsWith("!!IF ")) { |
509 | if(state.isEmpty() || state.top() == IN_CONDITION) { |
510 | QString test = line.mid(5, line.length()-(5+1)); |
511 | if(project->test(test)) |
512 | state.push(IN_CONDITION); |
513 | else |
514 | state.push(PENDING_CONDITION); |
515 | } else { |
516 | state.push(MET_CONDITION); |
517 | } |
518 | } else if(line.startsWith("!!ELIF ")) { |
519 | if(state.isEmpty()) { |
520 | warn_msg(WarnLogic, "(%s:%d): Unexpected else condition", |
521 | in.fileName().toLatin1().constData(), count); |
522 | } else if(state.top() == PENDING_CONDITION) { |
523 | QString test = line.mid(7, line.length()-(7+1)); |
524 | if(project->test(test)) { |
525 | state.pop(); |
526 | state.push(IN_CONDITION); |
527 | } |
528 | } else if(state.top() == IN_CONDITION) { |
529 | state.pop(); |
530 | state.push(MET_CONDITION); |
531 | } |
532 | } else if(line.startsWith("!!ELSE")) { |
533 | if(state.isEmpty()) { |
534 | warn_msg(WarnLogic, "(%s:%d): Unexpected else condition", |
535 | in.fileName().toLatin1().constData(), count); |
536 | } else if(state.top() == PENDING_CONDITION) { |
537 | state.pop(); |
538 | state.push(IN_CONDITION); |
539 | } else if(state.top() == IN_CONDITION) { |
540 | state.pop(); |
541 | state.push(MET_CONDITION); |
542 | } |
543 | } else if(line.startsWith("!!ENDIF")) { |
544 | if(state.isEmpty()) |
545 | warn_msg(WarnLogic, "(%s:%d): Unexpected endif", |
546 | in.fileName().toLatin1().constData(), count); |
547 | else |
548 | state.pop(); |
549 | } else if(state.isEmpty() || state.top() == IN_CONDITION) { |
550 | contents += project->expand(line, in.fileName(), count); |
551 | } |
552 | } |
553 | QFile out(outn); |
554 | if(out.exists() && out.open(QFile::ReadOnly)) { |
555 | QString old = QString::fromUtf8(out.readAll()); |
556 | if(contents == old) { |
557 | v["QMAKE_INTERNAL_INCLUDED_FILES"].append(in.fileName()); |
558 | continue; |
559 | } |
560 | out.close(); |
561 | if(!out.remove()) { |
562 | warn_msg(WarnLogic, "Cannot clear substitute '%s'", |
563 | out.fileName().toLatin1().constData()); |
564 | continue; |
565 | } |
566 | } |
567 | mkdir(QFileInfo(out).absolutePath()); |
568 | if(out.open(QFile::WriteOnly)) { |
569 | v["QMAKE_INTERNAL_INCLUDED_FILES"].append(in.fileName()); |
570 | out.write(contents.toUtf8()); |
571 | } else { |
572 | warn_msg(WarnLogic, "Cannot open substitute for output '%s'", |
573 | out.fileName().toLatin1().constData()); |
574 | } |
575 | } else { |
576 | warn_msg(WarnLogic, "Cannot open substitute for input '%s'", |
577 | in.fileName().toLatin1().constData()); |
578 | } |
579 | } |
580 | } |
581 | |
582 | int x; |
583 | |
584 | //build up a list of compilers |
585 | QList<Compiler> compilers; |
586 | { |
587 | const char *builtins[] = { "OBJECTS", "SOURCES", "PRECOMPILED_HEADER", 0 }; |
588 | for(x = 0; builtins[x]; ++x) { |
589 | Compiler compiler; |
590 | compiler.variable_in = builtins[x]; |
591 | compiler.flags = Compiler::CompilerBuiltin; |
592 | compiler.type = QMakeSourceFileInfo::TYPE_C; |
593 | if(!strcmp(builtins[x], "OBJECTS")) |
594 | compiler.flags |= Compiler::CompilerNoCheckDeps; |
595 | compilers.append(compiler); |
596 | } |
597 | for(QStringList::ConstIterator it = quc.begin(); it != quc.end(); ++it) { |
598 | const QStringList &inputs = v[(*it) + ".input"]; |
599 | for(x = 0; x < inputs.size(); ++x) { |
600 | Compiler compiler; |
601 | compiler.variable_in = inputs.at(x); |
602 | compiler.flags = Compiler::CompilerNoFlags; |
603 | if(v[(*it) + ".CONFIG"].indexOf( "ignore_no_exist") != -1) |
604 | compiler.flags |= Compiler::CompilerRemoveNoExist; |
605 | if(v[(*it) + ".CONFIG"].indexOf( "no_dependencies") != -1) |
606 | compiler.flags |= Compiler::CompilerNoCheckDeps; |
607 | |
608 | QString dep_type; |
609 | if(!project->isEmpty((*it) + ".dependency_type")) |
610 | dep_type = project->first((*it) + ".dependency_type"); |
611 | if (dep_type.isEmpty()) |
612 | compiler.type = QMakeSourceFileInfo::TYPE_UNKNOWN; |
613 | else if(dep_type == "TYPE_UI") |
614 | compiler.type = QMakeSourceFileInfo::TYPE_UI; |
615 | else |
616 | compiler.type = QMakeSourceFileInfo::TYPE_C; |
617 | compilers.append(compiler); |
618 | } |
619 | } |
620 | } |
621 | { //do the path fixifying |
622 | QStringList paths; |
623 | for(x = 0; x < compilers.count(); ++x) { |
624 | if(!paths.contains(compilers.at(x).variable_in)) |
625 | paths << compilers.at(x).variable_in; |
626 | } |
627 | paths << "INCLUDEPATH"<< "QMAKE_INTERNAL_INCLUDED_FILES"<< "PRECOMPILED_HEADER"; |
628 | for(int y = 0; y < paths.count(); y++) { |
629 | QStringList &l = v[paths[y]]; |
630 | for(QStringList::Iterator it = l.begin(); it != l.end(); ++it) { |
631 | if((*it).isEmpty()) |
632 | continue; |
633 | if(exists((*it))) |
634 | (*it) = fileFixify((*it)); |
635 | } |
636 | } |
637 | } |
638 | |
639 | if(noIO() || !doDepends()) |
640 | QMakeSourceFileInfo::setDependencyMode(QMakeSourceFileInfo::NonRecursive); |
641 | for(x = 0; x < compilers.count(); ++x) |
642 | initCompiler(compilers.at(x)); |
643 | |
644 | //merge actual compiler outputs into their variable_out. This is done last so that |
645 | //files are already properly fixified. |
646 | for(QStringList::Iterator it = quc.begin(); it != quc.end(); ++it) { |
647 | QString tmp_out = project->values((*it) + ".output").first(); |
648 | if(tmp_out.isEmpty()) |
649 | continue; |
650 | if(project->values((*it) + ".CONFIG").indexOf( "combine") != -1) { |
651 | QStringList &compilerInputs = project->values((*it) + ".input"); |
652 | // Don't generate compiler output if it doesn't have input. |
653 | if (compilerInputs.isEmpty() || project->values(compilerInputs.first()).isEmpty()) |
654 | continue; |
655 | if(tmp_out.indexOf("$") == -1) { |
656 | if(!verifyExtraCompiler((*it), QString())) //verify |
657 | continue; |
658 | QString out = fileFixify(tmp_out, Option::output_dir, Option::output_dir); |
659 | bool pre_dep = (project->values((*it) + ".CONFIG").indexOf( "target_predeps") != -1); |
660 | if(project->variables().contains((*it) + ".variable_out")) { |
661 | const QStringList &var_out = project->variables().value((*it) + ".variable_out"); |
662 | for(int i = 0; i < var_out.size(); ++i) { |
663 | QString v = var_out.at(i); |
664 | if(v == QLatin1String("SOURCES")) |
665 | v = "GENERATED_SOURCES"; |
666 | else if(v == QLatin1String("OBJECTS")) |
667 | pre_dep = false; |
668 | QStringList &list = project->values(v); |
669 | if(!list.contains(out)) |
670 | list.append(out); |
671 | } |
672 | } else if(project->values((*it) + ".CONFIG").indexOf( "no_link") == -1) { |
673 | QStringList &list = project->values("OBJECTS"); |
674 | pre_dep = false; |
675 | if(!list.contains(out)) |
676 | list.append(out); |
677 | } else { |
678 | QStringList &list = project->values("UNUSED_SOURCES"); |
679 | if(!list.contains(out)) |
680 | list.append(out); |
681 | } |
682 | if(pre_dep) { |
683 | QStringList &list = project->variables()["PRE_TARGETDEPS"]; |
684 | if(!list.contains(out)) |
685 | list.append(out); |
686 | } |
687 | } |
688 | } else { |
689 | QStringList &tmp = project->values((*it) + ".input"); |
690 | for(QStringList::Iterator it2 = tmp.begin(); it2 != tmp.end(); ++it2) { |
691 | const QStringList inputs = project->values((*it2)); |
692 | for(QStringList::ConstIterator input = inputs.constBegin(); input != inputs.constEnd(); ++input) { |
693 | if((*input).isEmpty()) |
694 | continue; |
695 | QString in = Option::fixPathToTargetOS((*input), false); |
696 | if(!verifyExtraCompiler((*it), in)) //verify |
697 | continue; |
698 | QString out = replaceExtraCompilerVariables(tmp_out, (*input), QString()); |
699 | out = fileFixify(out, Option::output_dir, Option::output_dir); |
700 | bool pre_dep = (project->values((*it) + ".CONFIG").indexOf( "target_predeps") != -1); |
701 | if(project->variables().contains((*it) + ".variable_out")) { |
702 | const QStringList &var_out = project->variables().value((*it) + ".variable_out"); |
703 | for(int i = 0; i < var_out.size(); ++i) { |
704 | QString v = var_out.at(i); |
705 | if(v == QLatin1String("SOURCES")) |
706 | v = "GENERATED_SOURCES"; |
707 | else if(v == QLatin1String("OBJECTS")) |
708 | pre_dep = false; |
709 | QStringList &list = project->values(v); |
710 | if(!list.contains(out)) |
711 | list.append(out); |
712 | } |
713 | } else if(project->values((*it) + ".CONFIG").indexOf( "no_link") == -1) { |
714 | pre_dep = false; |
715 | QStringList &list = project->values("OBJECTS"); |
716 | if(!list.contains(out)) |
717 | list.append(out); |
718 | } else { |
719 | QStringList &list = project->values("UNUSED_SOURCES"); |
720 | if(!list.contains(out)) |
721 | list.append(out); |
722 | } |
723 | if(pre_dep) { |
724 | QStringList &list = project->variables()["PRE_TARGETDEPS"]; |
725 | if(!list.contains(out)) |
726 | list.append(out); |
727 | } |
728 | } |
729 | } |
730 | } |
731 | } |
732 | |
733 | //handle dependencies |
734 | depHeuristicsCache.clear(); |
735 | if(!noIO()) { |
736 | // dependency paths |
737 | QStringList incDirs = v["DEPENDPATH"] + v[ "QMAKE_ABSOLUTE_SOURCE_PATH"]; |
738 | if(project->isActiveConfig("depend_includepath")) |
739 | incDirs += v["INCLUDEPATH"]; |
740 | if(!project->isActiveConfig("no_include_pwd")) { |
741 | QString pwd = qmake_getpwd(); |
742 | if(pwd.isEmpty()) |
743 | pwd = "."; |
744 | incDirs += pwd; |
745 | } |
746 | QList<QMakeLocalFileName> deplist; |
747 | for(QStringList::Iterator it = incDirs.begin(); it != incDirs.end(); ++it) |
748 | deplist.append(QMakeLocalFileName(unescapeFilePath((*it)))); |
749 | QMakeSourceFileInfo::setDependencyPaths(deplist); |
750 | debug_msg(1, "Dependency Directories: %s", incDirs.join( " :: ").toLatin1().constData()); |
751 | //cache info |
752 | if(project->isActiveConfig("qmake_cache")) { |
753 | QString cache_file; |
754 | if(!project->isEmpty("QMAKE_INTERNAL_CACHE_FILE")) { |
755 | cache_file = QDir::fromNativeSeparators(project->first("QMAKE_INTERNAL_CACHE_FILE")); |
756 | } else { |
757 | cache_file = ".qmake.internal.cache"; |
758 | if(project->isActiveConfig("build_pass")) |
759 | cache_file += ".BUILD."+ project->first( "BUILD_PASS"); |
760 | } |
761 | if(cache_file.indexOf( |
762 | cache_file.prepend(Option::output_dir + |
763 | QMakeSourceFileInfo::setCacheFile(cache_file); |
764 | } |
765 | |
766 | //add to dependency engine |
767 | for(x = 0; x < compilers.count(); ++x) { |
768 | const MakefileGenerator::Compiler &comp = compilers.at(x); |
769 | if(!(comp.flags & Compiler::CompilerNoCheckDeps)) |
770 | addSourceFiles(v[comp.variable_in], QMakeSourceFileInfo::SEEK_DEPS, |
771 | (QMakeSourceFileInfo::SourceFileType)comp.type); |
772 | } |
773 | } |
774 | |
775 | processSources(); //remove anything in SOURCES which is included (thus it need not be linked in) |
776 | |
777 | //all sources and generated sources must be turned into objects at some point (the one builtin compiler) |
778 | v["OBJECTS"] += createObjectList(v[ "SOURCES"]) + createObjectList(v[ "GENERATED_SOURCES"]); |
779 | |
780 | //Translation files |
781 | if(!project->isEmpty("TRANSLATIONS")) { |
782 | QStringList &trf = project->values("TRANSLATIONS"); |
783 | for(QStringList::Iterator it = trf.begin(); it != trf.end(); ++it) |
784 | (*it) = Option::fixPathToLocalOS((*it)); |
785 | } |
786 | |
787 | if(!project->isActiveConfig("no_include_pwd")) { //get the output_dir into the pwd |
788 | if(Option::output_dir != qmake_getpwd()) |
789 | project->values("INCLUDEPATH").append( "."); |
790 | } |
791 | |
792 | //fix up the target deps |
793 | QString fixpaths[] = { QString("PRE_TARGETDEPS"), QString( "POST_TARGETDEPS"), QString() }; |
794 | for(int path = 0; !fixpaths[path].isNull(); path++) { |
795 | QStringList &l = v[fixpaths[path]]; |
796 | for(QStringList::Iterator val_it = l.begin(); val_it != l.end(); ++val_it) { |
797 | if(!(*val_it).isEmpty()) |
798 | (*val_it) = escapeDependencyPath(Option::fixPathToTargetOS((*val_it), false, false)); |
799 | } |
800 | } |
801 | |
802 | //extra depends |
803 | if(!project->isEmpty("DEPENDS")) { |
804 | QStringList &l = v["DEPENDS"]; |
805 | for(QStringList::Iterator it = l.begin(); it != l.end(); ++it) { |
806 | QStringList files = v[(*it) + ".file"] + v[(*it) + ".files"]; //why do I support such evil things? |
807 | for(QStringList::Iterator file_it = files.begin(); file_it != files.end(); ++file_it) { |
808 | QStringList &out_deps = findDependencies(*file_it); |
809 | QStringList &in_deps = v[(*it) + ".depends"]; //even more evilness.. |
810 | for(QStringList::Iterator dep_it = in_deps.begin(); dep_it != in_deps.end(); ++dep_it) { |
811 | if(exists(*dep_it)) { |
812 | out_deps.append(*dep_it); |
813 | } else { |
814 | QString dir, regex = Option::fixPathToLocalOS((*dep_it)); |
815 | if(regex.lastIndexOf(Option::dir_sep) != -1) { |
816 | dir = regex.left(regex.lastIndexOf(Option::dir_sep) + 1); |
817 | regex.remove(0, dir.length()); |
818 | } |
819 | QStringList files = QDir(dir).entryList(QStringList(regex)); |
820 | if(files.isEmpty()) { |
821 | warn_msg(WarnLogic, "Dependency for [%s]: Not found %s", (*file_it).toLatin1().constData(), |
822 | (*dep_it).toLatin1().constData()); |
823 | } else { |
824 | for(int i = 0; i < files.count(); i++) |
825 | out_deps.append(dir + files[i]); |
826 | } |
827 | } |
828 | } |
829 | } |
830 | } |
831 | } |
832 | |
833 | // escape qmake command |
834 | QStringList &qmk = project->values("QMAKE_QMAKE"); |
835 | qmk = escapeFilePaths(qmk); |
836 | } |
837 | |
838 | bool |
839 | MakefileGenerator::processPrlFile(QString &file) |
840 | { |
841 | bool ret = false, try_replace_file=false; |
842 | QString meta_file, orig_file = file; |
843 | if(QMakeMetaInfo::libExists(file)) { |
844 | try_replace_file = true; |
845 | meta_file = file; |
846 | file = ""; |
847 | } else { |
848 | QString tmp = file; |
849 | int ext = tmp.lastIndexOf( |
850 | if(ext != -1) |
851 | tmp = tmp.left(ext); |
852 | meta_file = tmp; |
853 | } |
854 | // meta_file = fileFixify(meta_file); |
855 | QString real_meta_file = Option::fixPathToLocalOS(meta_file); |
856 | if(!meta_file.isEmpty()) { |
857 | QString f = fileFixify(real_meta_file, qmake_getpwd(), Option::output_dir); |
858 | if(QMakeMetaInfo::libExists(f)) { |
859 | QMakeMetaInfo libinfo; |
860 | debug_msg(1, "Processing PRL file: %s", real_meta_file.toLatin1().constData()); |
861 | if(!libinfo.readLib(f)) { |
862 | fprintf(stderr, "Error processing meta file: %s\n", real_meta_file.toLatin1().constData()); |
863 | } else if(project->isActiveConfig("no_read_prl_"+ libinfo.type().toLower())) { |
864 | debug_msg(2, "Ignored meta file %s [%s]", real_meta_file.toLatin1().constData(), libinfo.type().toLatin1().constData()); |
865 | } else { |
866 | ret = true; |
867 | QMap<QString, QStringList> &vars = libinfo.variables(); |
868 | for(QMap<QString, QStringList>::Iterator it = vars.begin(); it != vars.end(); ++it) |
869 | processPrlVariable(it.key(), it.value()); |
870 | if(try_replace_file && !libinfo.isEmpty("QMAKE_PRL_TARGET")) { |
871 | QString dir; |
872 | int slsh = real_meta_file.lastIndexOf(Option::dir_sep); |
873 | if(slsh != -1) |
874 | dir = real_meta_file.left(slsh+1); |
875 | file = libinfo.first("QMAKE_PRL_TARGET"); |
876 | if(QDir::isRelativePath(file)) |
877 | file.prepend(dir); |
878 | } |
879 | } |
880 | } |
881 | if(ret) { |
882 | QString mf = QMakeMetaInfo::findLib(meta_file); |
883 | if(project->values("QMAKE_PRL_INTERNAL_FILES").indexOf(mf) == -1) |
884 | project->values("QMAKE_PRL_INTERNAL_FILES").append(mf); |
885 | if(project->values("QMAKE_INTERNAL_INCLUDED_FILES").indexOf(mf) == -1) |
886 | project->values("QMAKE_INTERNAL_INCLUDED_FILES").append(mf); |
887 | } |
888 | } |
889 | if(try_replace_file && file.isEmpty()) { |
890 | #if 0 |
891 | warn_msg(WarnLogic, "Found prl [%s] file with no target [%s]!", meta_file.toLatin1().constData(), |
892 | orig_file.toLatin1().constData()); |
893 | #endif |
894 | file = orig_file; |
895 | } |
896 | return ret; |
897 | } |
898 | |
899 | void |
900 | MakefileGenerator::filterIncludedFiles(const QString &var) |
901 | { |
902 | QStringList &inputs = project->values(var); |
903 | for(QStringList::Iterator input = inputs.begin(); input != inputs.end(); ) { |
904 | if(QMakeSourceFileInfo::included((*input)) > 0) |
905 | input = inputs.erase(input); |
906 | else |
907 | ++input; |
908 | } |
909 | } |
910 | |
911 | void |
912 | MakefileGenerator::processPrlVariable(const QString &var, const QStringList &l) |
913 | { |
914 | if(var == "QMAKE_PRL_LIBS") { |
915 | QString where = "QMAKE_LIBS"; |
916 | if(!project->isEmpty("QMAKE_INTERNAL_PRL_LIBS")) |
917 | where = project->first("QMAKE_INTERNAL_PRL_LIBS"); |
918 | QStringList &out = project->values(where); |
919 | for(QStringList::ConstIterator it = l.begin(); it != l.end(); ++it) { |
920 | if(out.indexOf((*it)) == -1) |
921 | out.append((*it)); |
922 | } |
923 | } else if(var == "QMAKE_PRL_DEFINES") { |
924 | QStringList &out = project->values("DEFINES"); |
925 | for(QStringList::ConstIterator it = l.begin(); it != l.end(); ++it) { |
926 | if(out.indexOf((*it)) == -1 && |
927 | project->values("PRL_EXPORT_DEFINES").indexOf((*it)) == -1) |
928 | out.append((*it)); |
929 | } |
930 | } |
931 | } |
932 | |
933 | void |
934 | MakefileGenerator::processPrlFiles() |
935 | { |
936 | QHash<QString, bool> processed; |
937 | for(bool ret = false; true; ret = false) { |
938 | //read in any prl files included.. |
939 | QStringList l_out; |
940 | QString where = "QMAKE_LIBS"; |
941 | if(!project->isEmpty("QMAKE_INTERNAL_PRL_LIBS")) |
942 | where = project->first("QMAKE_INTERNAL_PRL_LIBS"); |
943 | QStringList &l = project->values(where); |
944 | for(QStringList::Iterator it = l.begin(); it != l.end(); ++it) { |
945 | QString file = (*it); |
946 | if(!processed.contains(file) && processPrlFile(file)) { |
947 | processed.insert(file, true); |
948 | ret = true; |
949 | } |
950 | if(!file.isEmpty()) |
951 | l_out.append(file); |
952 | } |
953 | if(ret) |
954 | l = l_out; |
955 | else |
956 | break; |
957 | } |
958 | } |
959 | |
960 | void |
961 | MakefileGenerator::writePrlFile(QTextStream &t) |
962 | { |
963 | QString target = project->first("TARGET"); |
964 | int slsh = target.lastIndexOf(Option::dir_sep); |
965 | if(slsh != -1) |
966 | target.remove(0, slsh + 1); |
967 | QString bdir = Option::output_dir; |
968 | if(bdir.isEmpty()) |
969 | bdir = qmake_getpwd(); |
970 | t << "QMAKE_PRL_BUILD_DIR = "<< bdir << endl; |
971 | |
972 | if(!project->projectFile().isEmpty() && project->projectFile() != "-") |
973 | t << "QMAKE_PRO_INPUT = "<< project->projectFile().section( |
974 | |
975 | if(!project->isEmpty("QMAKE_ABSOLUTE_SOURCE_PATH")) |
976 | t << "QMAKE_PRL_SOURCE_DIR = "<< project->first( "QMAKE_ABSOLUTE_SOURCE_PATH") << endl; |
977 | t << "QMAKE_PRL_TARGET = "<< target << endl; |
978 | if(!project->isEmpty("PRL_EXPORT_DEFINES")) |
979 | t << "QMAKE_PRL_DEFINES = "<< project->values( "PRL_EXPORT_DEFINES").join( " ") << endl; |
980 | if(!project->isEmpty("PRL_EXPORT_CFLAGS")) |
981 | t << "QMAKE_PRL_CFLAGS = "<< project->values( "PRL_EXPORT_CFLAGS").join( " ") << endl; |
982 | if(!project->isEmpty("PRL_EXPORT_CXXFLAGS")) |
983 | t << "QMAKE_PRL_CXXFLAGS = "<< project->values( "PRL_EXPORT_CXXFLAGS").join( " ") << endl; |
984 | if(!project->isEmpty("CONFIG")) |
985 | t << "QMAKE_PRL_CONFIG = "<< project->values( "CONFIG").join( " ") << endl; |
986 | if(!project->isEmpty("TARGET_VERSION_EXT")) |
987 | t << "QMAKE_PRL_VERSION = "<< project->first( "TARGET_VERSION_EXT") << endl; |
988 | else if(!project->isEmpty("VERSION")) |
989 | t << "QMAKE_PRL_VERSION = "<< project->first( "VERSION") << endl; |
990 | if(project->isActiveConfig("staticlib") || project->isActiveConfig( "explicitlib")) { |
991 | QStringList libs; |
992 | if(!project->isEmpty("QMAKE_INTERNAL_PRL_LIBS")) |
993 | libs = project->values("QMAKE_INTERNAL_PRL_LIBS"); |
994 | else |
995 | libs << "QMAKE_LIBS"; //obvious one |
996 | if(project->isActiveConfig("staticlib")) |
997 | libs << "QMAKE_LIBS_PRIVATE"; |
998 | t << "QMAKE_PRL_LIBS = "; |
999 | for(QStringList::Iterator it = libs.begin(); it != libs.end(); ++it) |
1000 | t << project->values((*it)).join(" ").replace( "\\\\") << " "; |
1001 | t << endl; |
1002 | } |
1003 | } |
1004 | |
1005 | bool |
1006 | MakefileGenerator::writeProjectMakefile() |
1007 | { |
1008 | usePlatformDir(); |
1009 | QTextStream t(&Option::output); |
1010 | |
1011 | //header |
1012 | writeHeader(t); |
1013 | |
1014 | QList<SubTarget*> targets; |
1015 | { |
1016 | QStringList builds = project->values("BUILDS"); |
1017 | for(QStringList::Iterator it = builds.begin(); it != builds.end(); ++it) { |
1018 | SubTarget *st = new SubTarget; |
1019 | targets.append(st); |
1020 | st->makefile = "$(MAKEFILE)."+ (*it); |
1021 | st->name = (*it); |
1022 | st->target = project->isEmpty((*it) + ".target") ? (*it) : project->first((*it) + ".target"); |
1023 | } |
1024 | } |
1025 | if(project->isActiveConfig("build_all")) { |
1026 | t << "first: all"<< endl; |
1027 | QList<SubTarget*>::Iterator it; |
1028 | |
1029 | //install |
1030 | t << "install: "; |
1031 | for(it = targets.begin(); it != targets.end(); ++it) |
1032 | t << (*it)->target << "-install "; |
1033 | t << endl; |
1034 | |
1035 | //uninstall |
1036 | t << "uninstall: "; |
1037 | for(it = targets.begin(); it != targets.end(); ++it) |
1038 | t << (*it)->target << "-uninstall "; |
1039 | t << endl; |
1040 | } else { |
1041 | t << "first: "<< targets.first()->target << endl |
1042 | << "install: "<< targets.first()->target << "-install"<< endl |
1043 | << "uninstall: "<< targets.first()->target << "-uninstall"<< endl; |
1044 | } |
1045 | |
1046 | writeSubTargets(t, targets, SubTargetsNoFlags); |
1047 | if(!project->isActiveConfig("no_autoqmake")) { |
1048 | for(QList<SubTarget*>::Iterator it = targets.begin(); it != targets.end(); ++it) |
1049 | t << (*it)->makefile << ": "<< |
1050 | Option::fixPathToTargetOS(fileFixify(Option::output.fileName())) << endl; |
1051 | } |
1052 | qDeleteAll(targets); |
1053 | return true; |
1054 | } |
1055 | |
1056 | bool |
1057 | MakefileGenerator::write() |
1058 | { |
1059 | if(!project) |
1060 | return false; |
1061 | writePrlFile(); |
1062 | if(Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE || //write makefile |
1063 | Option::qmake_mode == Option::QMAKE_GENERATE_PROJECT) { |
1064 | QTextStream t(&Option::output); |
1065 | if(!writeMakefile(t)) { |
1066 | #if 1 |
1067 | warn_msg(WarnLogic, "Unable to generate output for: %s [TEMPLATE %s]", |
1068 | Option::output.fileName().toLatin1().constData(), |
1069 | project->first("TEMPLATE").toLatin1().constData()); |
1070 | if(Option::output.exists()) |
1071 | Option::output.remove(); |
1072 | #endif |
1073 | } |
1074 | } |
1075 | return true; |
1076 | } |
1077 | |
1078 | QString |
1079 | MakefileGenerator::prlFileName(bool fixify) |
1080 | { |
1081 | QString ret = project->first("TARGET_PRL");; |
1082 | if(ret.isEmpty()) |
1083 | ret = project->first("TARGET"); |
1084 | int slsh = ret.lastIndexOf(Option::dir_sep); |
1085 | if(slsh != -1) |
1086 | ret.remove(0, slsh); |
1087 | if(!ret.endsWith(Option::prl_ext)) { |
1088 | int dot = ret.indexOf( |
1089 | if(dot != -1) |
1090 | ret.truncate(dot); |
1091 | ret += Option::prl_ext; |
1092 | } |
1093 | if(!project->isEmpty("QMAKE_BUNDLE")) |
1094 | ret.prepend(project->first("QMAKE_BUNDLE") + Option::dir_sep); |
1095 | if(fixify) { |
1096 | if(!project->isEmpty("DESTDIR")) |
1097 | ret.prepend(project->first("DESTDIR")); |
1098 | ret = Option::fixPathToLocalOS(fileFixify(ret, qmake_getpwd(), Option::output_dir)); |
1099 | } |
1100 | return ret; |
1101 | } |
1102 | |
1103 | void |
1104 | MakefileGenerator::writePrlFile() |
1105 | { |
1106 | if((Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE || |
1107 | Option::qmake_mode == Option::QMAKE_GENERATE_PRL) |
1108 | && project->values("QMAKE_FAILED_REQUIREMENTS").isEmpty() |
1109 | && project->isActiveConfig("create_prl") |
1110 | && (project->first("TEMPLATE") == "lib" |
1111 | || project->first("TEMPLATE") == "vclib") |
1112 | && (!project->isActiveConfig("plugin") || project->isActiveConfig( "static"))) { //write prl file |
1113 | QString local_prl = prlFileName(); |
1114 | QString prl = fileFixify(local_prl); |
1115 | mkdir(fileInfo(local_prl).path()); |
1116 | QFile ft(local_prl); |
1117 | if(ft.open(QIODevice::WriteOnly)) { |
1118 | project->values("ALL_DEPS").append(prl); |
1119 | project->values("QMAKE_INTERNAL_PRL_FILE").append(prl); |
1120 | QTextStream t(&ft); |
1121 | writePrlFile(t); |
1122 | } |
1123 | } |
1124 | } |
1125 | |
1126 | // Manipulate directories, so it's possible to build |
1127 | // several cross-platform targets concurrently |
1128 | void |
1129 | MakefileGenerator::usePlatformDir() |
1130 | { |
1131 | QString pltDir(project->first("QMAKE_PLATFORM_DIR")); |
1132 | if(pltDir.isEmpty()) |
1133 | return; |
1134 | QChar sep = QDir::separator(); |
1135 | QString slashPltDir = sep + pltDir; |
1136 | |
1137 | QString dirs[] = { QString("OBJECTS_DIR"), QString( "DESTDIR"), QString( "QMAKE_PKGCONFIG_DESTDIR"), |
1138 | QString("SUBLIBS_DIR"), QString( "DLLDESTDIR"), QString( "QMAKE_LIBTOOL_DESTDIR"), |
1139 | QString("PRECOMPILED_DIR"), QString( "QMAKE_LIBDIR_QT"), QString() }; |
1140 | for(int i = 0; !dirs[i].isEmpty(); ++i) { |
1141 | QString filePath = project->first(dirs[i]); |
1142 | project->values(dirs[i]) = QStringList(filePath + (filePath.isEmpty() ? pltDir : slashPltDir)); |
1143 | } |
1144 | |
1145 | QString libs[] = { QString("QMAKE_LIBS_QT"), QString( "QMAKE_LIBS_QT_THREAD"), QString( "QMAKE_LIBS_QT_ENTRY"), QString() }; |
1146 | for(int i = 0; !libs[i].isEmpty(); ++i) { |
1147 | QString filePath = project->first(libs[i]); |
1148 | int fpi = filePath.lastIndexOf(sep); |
1149 | if(fpi == -1) |
1150 | project->values(libs[i]).prepend(pltDir + sep); |
1151 | else |
1152 | project->values(libs[i]) = QStringList(filePath.left(fpi) + slashPltDir + filePath.mid(fpi)); |
1153 | } |
1154 | } |
1155 | |
1156 | void |
1157 | MakefileGenerator::writeObj(QTextStream &t, const QString &src) |
1158 | { |
1159 | QStringList &srcl = project->values(src); |
1160 | QStringList objl = createObjectList(srcl); |
1161 | |
1162 | QStringList::Iterator oit = objl.begin(); |
1163 | QStringList::Iterator sit = srcl.begin(); |
1164 | QString stringSrc("$src"); |
1165 | QString stringObj("$obj"); |
1166 | for(;sit != srcl.end() && oit != objl.end(); ++oit, ++sit) { |
1167 | if((*sit).isEmpty()) |
1168 | continue; |
1169 | |
1170 | t << escapeDependencyPath((*oit)) << ": "<< escapeDependencyPath((*sit)) << " "<< escapeDependencyPaths(findDependencies((*sit))).join( " \\\n\t\t"); |
1171 | |
1172 | QString comp, cimp; |
1173 | for(QStringList::Iterator cppit = Option::cpp_ext.begin(); cppit != Option::cpp_ext.end(); ++cppit) { |
1174 | if((*sit).endsWith((*cppit))) { |
1175 | comp = "QMAKE_RUN_CXX"; |
1176 | cimp = "QMAKE_RUN_CXX_IMP"; |
1177 | break; |
1178 | } |
1179 | } |
1180 | if(comp.isEmpty()) { |
1181 | comp = "QMAKE_RUN_CC"; |
1182 | cimp = "QMAKE_RUN_CC_IMP"; |
1183 | } |
1184 | bool use_implicit_rule = !project->isEmpty(cimp); |
1185 | use_implicit_rule = false; |
1186 | if(use_implicit_rule) { |
1187 | if(!project->isEmpty("OBJECTS_DIR")) { |
1188 | use_implicit_rule = false; |
1189 | } else { |
1190 | int dot = (*sit).lastIndexOf( |
1191 | if(dot == -1 || ((*sit).left(dot) + Option::obj_ext != (*oit))) |
1192 | use_implicit_rule = false; |
1193 | } |
1194 | } |
1195 | if (!use_implicit_rule && !project->isEmpty(comp)) { |
1196 | QString p = var(comp), srcf(*sit); |
1197 | p.replace(stringSrc, escapeFilePath(srcf)); |
1198 | p.replace(stringObj, escapeFilePath((*oit))); |
1199 | t << "\n\t"<< p; |
1200 | } |
1201 | t << endl << endl; |
1202 | } |
1203 | } |
1204 | |
1205 | QString |
1206 | MakefileGenerator::filePrefixRoot(const QString &root, const QString &path) |
1207 | { |
1208 | QString ret(root + path); |
1209 | if(path.length() > 2 && path[1] == |
1210 | ret = QString(path.mid(0, 2) + root + path.mid(2)); |
1211 | while(ret.endsWith("\\")) |
1212 | ret = ret.left(ret.length()-1); |
1213 | return ret; |
1214 | } |
1215 | |
1216 | void |
1217 | MakefileGenerator::writeInstalls(QTextStream &t, const QString &installs, bool noBuild) |
1218 | { |
1219 | QString rm_dir_contents("-$(DEL_FILE)"); |
1220 | if (!isWindowsShell()) //ick |
1221 | rm_dir_contents = "-$(DEL_FILE) -r"; |
1222 | |
1223 | QString all_installs, all_uninstalls; |
1224 | QStringList &l = project->values(installs); |
1225 | for(QStringList::Iterator it = l.begin(); it != l.end(); ++it) { |
1226 | QString pvar = (*it) + ".path"; |
1227 | if(project->values((*it) + ".CONFIG").indexOf( "no_path") == -1 && |
1228 | project->values((*it) + ".CONFIG").indexOf( "dummy_install") == -1 && |
1229 | project->values(pvar).isEmpty()) { |
1230 | warn_msg(WarnLogic, "%s is not defined: install target not created\n", pvar.toLatin1().constData()); |
1231 | continue; |
1232 | } |
1233 | |
1234 | bool do_default = true; |
1235 | const QString root = "$(INSTALL_ROOT)"; |
1236 | QString target, dst; |
1237 | if(project->values((*it) + ".CONFIG").indexOf( "no_path") == -1 && |
1238 | project->values((*it) + ".CONFIG").indexOf( "dummy_install") == -1) { |
1239 | dst = fileFixify(unescapeFilePath(project->values(pvar).first()), FileFixifyAbsolute, false); |
1240 | if(!dst.endsWith(Option::dir_sep)) |
1241 | dst += Option::dir_sep; |
1242 | } |
1243 | dst = escapeFilePath(dst); |
1244 | |
1245 | QStringList tmp, uninst = project->values((*it) + ".uninstall"); |
1246 | //other |
1247 | tmp = project->values((*it) + ".extra"); |
1248 | if(tmp.isEmpty()) |
1249 | tmp = project->values((*it) + ".commands"); //to allow compatible name |
1250 | if(!tmp.isEmpty()) { |
1251 | do_default = false; |
1252 | if(!target.isEmpty()) |
1253 | target += "\n\t"; |
1254 | target += tmp.join(" "); |
1255 | } |
1256 | //masks |
1257 | tmp = findFilesInVPATH(project->values((*it) + ".files"), VPATH_NoFixify); |
1258 | tmp = fileFixify(tmp, FileFixifyAbsolute); |
1259 | if(!tmp.isEmpty()) { |
1260 | if(!target.isEmpty()) |
1261 | target += "\n"; |
1262 | do_default = false; |
1263 | for(QStringList::Iterator wild_it = tmp.begin(); wild_it != tmp.end(); ++wild_it) { |
1264 | QString wild = Option::fixPathToTargetOS((*wild_it), false, false); |
1265 | QString dirstr = qmake_getpwd(), filestr = wild; |
1266 | int slsh = filestr.lastIndexOf(Option::dir_sep); |
1267 | if(slsh != -1) { |
1268 | dirstr = filestr.left(slsh+1); |
1269 | filestr.remove(0, slsh+1); |
1270 | } |
1271 | if(!dirstr.endsWith(Option::dir_sep)) |
1272 | dirstr += Option::dir_sep; |
1273 | bool is_target = (wild == fileFixify(var("TARGET"), FileFixifyAbsolute)); |
1274 | if(is_target || exists(wild)) { //real file or target |
1275 | QString file = wild; |
1276 | QFileInfo fi(fileInfo(wild)); |
1277 | if(!target.isEmpty()) |
1278 | target += "\t"; |
1279 | QString dst_file = filePrefixRoot(root, dst); |
1280 | if(fi.isDir() && project->isActiveConfig("copy_dir_files")) { |
1281 | if(!dst_file.endsWith(Option::dir_sep)) |
1282 | dst_file += Option::dir_sep; |
1283 | dst_file += fi.fileName(); |
1284 | } |
1285 | QString cmd; |
1286 | if (fi.isDir()) |
1287 | cmd = "-$(INSTALL_DIR)"; |
1288 | else if (is_target || fi.isExecutable()) |
1289 | cmd = "-$(INSTALL_PROGRAM)"; |
1290 | else |
1291 | cmd = "-$(INSTALL_FILE)"; |
1292 | cmd += " "+ escapeFilePath(wild) + " "+ dst_file + "\n"; |
1293 | target += cmd; |
1294 | if(!project->isActiveConfig("debug") && !project->isActiveConfig( "nostrip") && |
1295 | !fi.isDir() && fi.isExecutable() && !project->isEmpty("QMAKE_STRIP")) |
1296 | target += QString("\t-") + var( "QMAKE_STRIP") + " "+ |
1297 | filePrefixRoot(root, fileFixify(dst + filestr, FileFixifyAbsolute, false)) + "\n"; |
1298 | if(!uninst.isEmpty()) |
1299 | uninst.append("\n\t"); |
1300 | uninst.append(rm_dir_contents + " "+ filePrefixRoot(root, fileFixify(dst + filestr, FileFixifyAbsolute, false))); |
1301 | continue; |
1302 | } |
1303 | QString local_dirstr = Option::fixPathToLocalOS(dirstr, true); |
1304 | QStringList files = QDir(local_dirstr).entryList(QStringList(filestr)); |
1305 | const QStringList &installConfigValues = project->values((*it) + ".CONFIG"); |
1306 | if (installConfigValues.contains("no_check_exist") && files.isEmpty()) { |
1307 | if(!target.isEmpty()) |
1308 | target += "\t"; |
1309 | QString dst_file = filePrefixRoot(root, dst); |
1310 | QFileInfo fi(fileInfo(wild)); |
1311 | QString cmd; |
1312 | if (installConfigValues.contains("directory")) { |
1313 | cmd = QLatin1String("-$(INSTALL_DIR)"); |
1314 | if (!dst_file.endsWith(Option::dir_sep)) |
1315 | dst_file += Option::dir_sep; |
1316 | dst_file += fi.fileName(); |
1317 | } else if (installConfigValues.contains("executable")) { |
1318 | cmd = QLatin1String("-$(INSTALL_PROGRAM)"); |
1319 | } else if (installConfigValues.contains("data")) { |
1320 | cmd = QLatin1String("-$(INSTALL_FILE)"); |
1321 | } else { |
1322 | cmd = QString(fi.isExecutable() ? "-$(INSTALL_PROGRAM)": "-$(INSTALL_FILE)"); |
1323 | } |
1324 | cmd += " "+ wild + " "+ dst_file + "\n"; |
1325 | target += cmd; |
1326 | if(!uninst.isEmpty()) |
1327 | uninst.append("\n\t"); |
1328 | uninst.append(rm_dir_contents + " "+ filePrefixRoot(root, fileFixify(dst + filestr, FileFixifyAbsolute, false))); |
1329 | } |
1330 | for(int x = 0; x < files.count(); x++) { |
1331 | QString file = files[x]; |
1332 | if(file == "."|| file == "..") //blah |
1333 | continue; |
1334 | if(!uninst.isEmpty()) |
1335 | uninst.append("\n\t"); |
1336 | uninst.append(rm_dir_contents + " "+ filePrefixRoot(root, fileFixify(dst + file, FileFixifyAbsolute, false))); |
1337 | QFileInfo fi(fileInfo(dirstr + file)); |
1338 | if(!target.isEmpty()) |
1339 | target += "\t"; |
1340 | QString dst_file = filePrefixRoot(root, fileFixify(dst, FileFixifyAbsolute, false)); |
1341 | if(fi.isDir() && project->isActiveConfig("copy_dir_files")) { |
1342 | if(!dst_file.endsWith(Option::dir_sep)) |
1343 | dst_file += Option::dir_sep; |
1344 | dst_file += fi.fileName(); |
1345 | } |
1346 | QString cmd = QString(fi.isDir() ? "-$(INSTALL_DIR)": "-$(INSTALL_FILE)") + " "+ |
1347 | dirstr + file + " "+ dst_file + "\n"; |
1348 | target += cmd; |
1349 | if(!project->isActiveConfig("debug") && !project->isActiveConfig( "nostrip") && |
1350 | !fi.isDir() && fi.isExecutable() && !project->isEmpty("QMAKE_STRIP")) |
1351 | target += QString("\t-") + var( "QMAKE_STRIP") + " "+ |
1352 | filePrefixRoot(root, fileFixify(dst + file, FileFixifyAbsolute, false)) + |
1353 | "\n"; |
1354 | } |
1355 | } |
1356 | } |
1357 | //default? |
1358 | if(do_default) { |
1359 | target = defaultInstall((*it)); |
1360 | uninst = project->values((*it) + ".uninstall"); |
1361 | } |
1362 | |
1363 | if(!target.isEmpty() || project->values((*it) + ".CONFIG").indexOf( "dummy_install") != -1) { |
1364 | if(noBuild || project->values((*it) + ".CONFIG").indexOf( "no_build") != -1) |
1365 | t << "install_"<< (*it) << ":"; |
1366 | else if(project->isActiveConfig("build_all")) |
1367 | t << "install_"<< (*it) << ": all"; |
1368 | else |
1369 | t << "install_"<< (*it) << ": first"; |
1370 | const QStringList &deps = project->values((*it) + ".depends"); |
1371 | if(!deps.isEmpty()) { |
1372 | for(QStringList::ConstIterator dep_it = deps.begin(); dep_it != deps.end(); ++dep_it) { |
1373 | QString targ = var((*dep_it) + ".target"); |
1374 | if(targ.isEmpty()) |
1375 | targ = (*dep_it); |
1376 | t << " "<< escapeDependencyPath(targ); |
1377 | } |
1378 | } |
1379 | if(project->isEmpty("QMAKE_NOFORCE")) |
1380 | t << " FORCE"; |
1381 | t << "\n\t"; |
1382 | const QStringList &dirs = project->values(pvar); |
1383 | for(QStringList::ConstIterator pit = dirs.begin(); pit != dirs.end(); ++pit) { |
1384 | QString tmp_dst = fileFixify((*pit), FileFixifyAbsolute, false); |
1385 | if (!isWindowsShell() && !tmp_dst.endsWith(Option::dir_sep)) |
1386 | tmp_dst += Option::dir_sep; |
1387 | t << mkdir_p_asstring(filePrefixRoot(root, tmp_dst)) << "\n\t"; |
1388 | } |
1389 | t << target << endl << endl; |
1390 | if(!uninst.isEmpty()) { |
1391 | t << "uninstall_"<< (*it) << ": "; |
1392 | if(project->isEmpty("QMAKE_NOFORCE")) |
1393 | t << " FORCE"; |
1394 | t << "\n\t" |
1395 | << uninst.join(" ") << "\n\t" |
1396 | << "-$(DEL_DIR) "<< filePrefixRoot(root, dst) << " "<< endl << endl; |
1397 | } |
1398 | t << endl; |
1399 | |
1400 | if(project->values((*it) + ".CONFIG").indexOf( "no_default_install") == -1) { |
1401 | all_installs += QString("install_") + (*it) + " "; |
1402 | if(!uninst.isEmpty()) |
1403 | all_uninstalls += "uninstall_"+ (*it) + " "; |
1404 | } |
1405 | } else { |
1406 | debug_msg(1, "no definition for install %s: install target not created",(*it).toLatin1().constData()); |
1407 | } |
1408 | } |
1409 | t << "install: "<< var( "INSTALLDEPS") << " "<< all_installs; |
1410 | if(project->isEmpty("QMAKE_NOFORCE")) |
1411 | t << " FORCE"; |
1412 | t << "\n\n"; |
1413 | t << "uninstall: "<< all_uninstalls << " "<< var( "UNINSTALLDEPS"); |
1414 | if(project->isEmpty("QMAKE_NOFORCE")) |
1415 | t << " FORCE"; |
1416 | t << "\n\n"; |
1417 | } |
1418 | |
1419 | QString |
1420 | MakefileGenerator::var(const QString &var) |
1421 | { |
1422 | return val(project->values(var)); |
1423 | } |
1424 | |
1425 | QString |
1426 | MakefileGenerator::val(const QStringList &varList) |
1427 | { |
1428 | return valGlue(varList, "", " ", ""); |
1429 | } |
1430 | |
1431 | QString |
1432 | MakefileGenerator::varGlue(const QString &var, const QString &before, const QString &glue, const QString &after) |
1433 | { |
1434 | return valGlue(project->values(var), before, glue, after); |
1435 | } |
1436 | |
1437 | QString |
1438 | MakefileGenerator::valGlue(const QStringList &varList, const QString &before, const QString &glue, const QString &after) |
1439 | { |
1440 | QString ret; |
1441 | for(QStringList::ConstIterator it = varList.begin(); it != varList.end(); ++it) { |
1442 | if(!(*it).isEmpty()) { |
1443 | if(!ret.isEmpty()) |
1444 | ret += glue; |
1445 | ret += (*it); |
1446 | } |
1447 | } |
1448 | return ret.isEmpty() ? QString("") : before + ret + after; |
1449 | } |
1450 | |
1451 | |
1452 | QString |
1453 | MakefileGenerator::varList(const QString &var) |
1454 | { |
1455 | return valList(project->values(var)); |
1456 | } |
1457 | |
1458 | QString |
1459 | MakefileGenerator::valList(const QStringList &varList) |
1460 | { |
1461 | return valGlue(varList, "", " \\\n\t\t", ""); |
1462 | } |
1463 | |
1464 | QStringList |
1465 | MakefileGenerator::createObjectList(const QStringList &sources) |
1466 | { |
1467 | QStringList ret; |
1468 | QString objdir; |
1469 | if(!project->values("OBJECTS_DIR").isEmpty()) |
1470 | objdir = project->first("OBJECTS_DIR"); |
1471 | for(QStringList::ConstIterator it = sources.begin(); it != sources.end(); ++it) { |
1472 | QFileInfo fi(fileInfo(Option::fixPathToLocalOS((*it)))); |
1473 | QString dir; |
1474 | if(objdir.isEmpty() && project->isActiveConfig("object_with_source")) { |
1475 | QString fName = Option::fixPathToTargetOS((*it), false); |
1476 | int dl = fName.lastIndexOf(Option::dir_sep); |
1477 | if(dl != -1) |
1478 | dir = fName.left(dl + 1); |
1479 | } else { |
1480 | dir = objdir; |
1481 | } |
1482 | ret.append(dir + fi.completeBaseName() + Option::obj_ext); |
1483 | } |
1484 | return ret; |
1485 | } |
1486 | |
1487 | ReplaceExtraCompilerCacheKey::ReplaceExtraCompilerCacheKey(const QString &v, const QStringList &i, const QStringList &o) |
1488 | { |
1489 | static QString doubleColon = QLatin1String("::"); |
1490 | |
1491 | hash = 0; |
1492 | pwd = qmake_getpwd(); |
1493 | var = v; |
1494 | { |
1495 | QStringList il = i; |
1496 | il.sort(); |
1497 | in = il.join(doubleColon); |
1498 | } |
1499 | { |
1500 | QStringList ol = o; |
1501 | ol.sort(); |
1502 | out = ol.join(doubleColon); |
1503 | } |
1504 | } |
1505 | |
1506 | bool ReplaceExtraCompilerCacheKey::operator==(const ReplaceExtraCompilerCacheKey &f) const |
1507 | { |
1508 | return (hashCode() == f.hashCode() && |
1509 | f.in == in && |
1510 | f.out == out && |
1511 | f.var == var && |
1512 | f.pwd == pwd); |
1513 | } |
1514 | |
1515 | |
1516 | QString |
1517 | MakefileGenerator::replaceExtraCompilerVariables(const QString &orig_var, const QStringList &in, const QStringList &out) |
1518 | { |
1519 | //lazy cache |
1520 | ReplaceExtraCompilerCacheKey cacheKey(orig_var, in, out); |
1521 | QString cacheVal = extraCompilerVariablesCache.value(cacheKey); |
1522 | if(!cacheVal.isNull()) |
1523 | return cacheVal; |
1524 | |
1525 | //do the work |
1526 | QString ret = orig_var; |
1527 | QRegExp reg_var("\\$\\{.*\\}"); |
1528 | reg_var.setMinimal(true); |
1529 | for(int rep = 0; (rep = reg_var.indexIn(ret, rep)) != -1; ) { |
1530 | QStringList val; |
1531 | const QString var = ret.mid(rep + 2, reg_var.matchedLength() - 3); |
1532 | bool filePath = false; |
1533 | if(val.isEmpty() && var.startsWith(QLatin1String("QMAKE_VAR_"))) { |
1534 | const QString varname = var.mid(10); |
1535 | val += project->values(varname); |
1536 | } |
1537 | if(val.isEmpty() && var.startsWith(QLatin1String("QMAKE_VAR_FIRST_"))) { |
1538 | const QString varname = var.mid(16); |
1539 | val += project->first(varname); |
1540 | } |
1541 | |
1542 | if(val.isEmpty() && !in.isEmpty()) { |
1543 | if(var.startsWith(QLatin1String("QMAKE_FUNC_FILE_IN_"))) { |
1544 | filePath = true; |
1545 | const QString funcname = var.mid(19); |
1546 | val += project->expand(funcname, QList<QStringList>() << in); |
1547 | } else if(var == QLatin1String("QMAKE_FILE_BASE") || var == QLatin1String( "QMAKE_FILE_IN_BASE")) { |
1548 | //filePath = true; |
1549 | for(int i = 0; i < in.size(); ++i) { |
1550 | QFileInfo fi(fileInfo(Option::fixPathToLocalOS(in.at(i)))); |
1551 | QString base = fi.completeBaseName(); |
1552 | if(base.isNull()) |
1553 | base = fi.fileName(); |
1554 | val += base; |
1555 | } |
1556 | } else if(var == QLatin1String("QMAKE_FILE_EXT")) { |
1557 | filePath = true; |
1558 | for(int i = 0; i < in.size(); ++i) { |
1559 | QFileInfo fi(fileInfo(Option::fixPathToLocalOS(in.at(i)))); |
1560 | QString ext; |
1561 | // Ensure complementarity with QMAKE_FILE_BASE |
1562 | int baseLen = fi.completeBaseName().length(); |
1563 | if(baseLen == 0) |
1564 | ext = fi.fileName(); |
1565 | else |
1566 | ext = fi.fileName().remove(0, baseLen); |
1567 | val += ext; |
1568 | } |
1569 | } else if(var == QLatin1String("QMAKE_FILE_PATH") || var == QLatin1String( "QMAKE_FILE_IN_PATH")) { |
1570 | filePath = true; |
1571 | for(int i = 0; i < in.size(); ++i) |
1572 | val += fileInfo(Option::fixPathToLocalOS(in.at(i))).path(); |
1573 | } else if(var == QLatin1String("QMAKE_FILE_NAME") || var == QLatin1String( "QMAKE_FILE_IN")) { |
1574 | filePath = true; |
1575 | for(int i = 0; i < in.size(); ++i) |
1576 | val += fileInfo(Option::fixPathToLocalOS(in.at(i))).filePath(); |
1577 | |
1578 | } |
1579 | } |
1580 | if(val.isEmpty() && !out.isEmpty()) { |
1581 | if(var.startsWith(QLatin1String("QMAKE_FUNC_FILE_OUT_"))) { |
1582 | filePath = true; |
1583 | const QString funcname = var.mid(20); |
1584 | val += project->expand(funcname, QList<QStringList>() << out); |
1585 | } else if(var == QLatin1String("QMAKE_FILE_OUT")) { |
1586 | filePath = true; |
1587 | for(int i = 0; i < out.size(); ++i) |
1588 | val += fileInfo(Option::fixPathToLocalOS(out.at(i))).filePath(); |
1589 | } else if(var == QLatin1String("QMAKE_FILE_OUT_BASE")) { |
1590 | //filePath = true; |
1591 | for(int i = 0; i < out.size(); ++i) { |
1592 | QFileInfo fi(fileInfo(Option::fixPathToLocalOS(out.at(i)))); |
1593 | QString base = fi.completeBaseName(); |
1594 | if(base.isNull()) |
1595 | base = fi.fileName(); |
1596 | val += base; |
1597 | } |
1598 | } |
1599 | } |
1600 | if(val.isEmpty() && var.startsWith(QLatin1String("QMAKE_FUNC_"))) { |
1601 | const QString funcname = var.mid(11); |
1602 | val += project->expand(funcname, QList<QStringList>() << in << out); |
1603 | } |
1604 | |
1605 | if(!val.isEmpty()) { |
1606 | QString fullVal; |
1607 | if(filePath) { |
1608 | for(int i = 0; i < val.size(); ++i) { |
1609 | const QString file = Option::fixPathToTargetOS(unescapeFilePath(val.at(i)), false); |
1610 | if(!fullVal.isEmpty()) |
1611 | fullVal += " "; |
1612 | fullVal += escapeFilePath(file); |
1613 | } |
1614 | } else { |
1615 | fullVal = val.join(" "); |
1616 | } |
1617 | ret.replace(rep, reg_var.matchedLength(), fullVal); |
1618 | rep += fullVal.length(); |
1619 | } else { |
1620 | rep += reg_var.matchedLength(); |
1621 | } |
1622 | } |
1623 | |
1624 | //cache the value |
1625 | extraCompilerVariablesCache.insert(cacheKey, ret); |
1626 | return ret; |
1627 | } |
1628 | |
1629 | bool |
1630 | MakefileGenerator::verifyExtraCompiler(const QString &comp, const QString &file_unfixed) |
1631 | { |
1632 | if(noIO()) |
1633 | return false; |
1634 | const QString file = Option::fixPathToLocalOS(file_unfixed); |
1635 | |
1636 | if(project->values(comp + ".CONFIG").indexOf( "moc_verify") != -1) { |
1637 | if(!file.isNull()) { |
1638 | QMakeSourceFileInfo::addSourceFile(file, QMakeSourceFileInfo::SEEK_MOCS); |
1639 | if(!mocable(file)) { |
1640 | return false; |
1641 | } else { |
1642 | project->values("MOCABLES").append(file); |
1643 | } |
1644 | } |
1645 | } else if(project->values(comp + ".CONFIG").indexOf( "function_verify") != -1) { |
1646 | QString tmp_out = project->values(comp + ".output").first(); |
1647 | if(tmp_out.isEmpty()) |
1648 | return false; |
1649 | QStringList verify_function = project->values(comp + ".verify_function"); |
1650 | if(verify_function.isEmpty()) |
1651 | return false; |
1652 | |
1653 | for(int i = 0; i < verify_function.size(); ++i) { |
1654 | bool invert = false; |
1655 | QString verify = verify_function.at(i); |
1656 | if(verify.at(0) == QLatin1Char( |
1657 | invert = true; |
1658 | verify = verify.mid(1); |
1659 | } |
1660 | |
1661 | if(project->values(comp + ".CONFIG").indexOf( "combine") != -1) { |
1662 | bool pass = project->test(verify, QList<QStringList>() << QStringList(tmp_out) << QStringList(file)); |
1663 | if(invert) |
1664 | pass = !pass; |
1665 | if(!pass) |
1666 | return false; |
1667 | } else { |
1668 | QStringList &tmp = project->values(comp + ".input"); |
1669 | for(QStringList::Iterator it = tmp.begin(); it != tmp.end(); ++it) { |
1670 | QStringList &inputs = project->values((*it)); |
1671 | for(QStringList::Iterator input = inputs.begin(); input != inputs.end(); ++input) { |
1672 | if((*input).isEmpty()) |
1673 | continue; |
1674 | QString in = fileFixify(Option::fixPathToTargetOS((*input), false)); |
1675 | if(in == file) { |
1676 | bool pass = project->test(verify, |
1677 | QList<QStringList>() << QStringList(replaceExtraCompilerVariables(tmp_out, (*input), QString())) << |
1678 | QStringList(file)); |
1679 | if(invert) |
1680 | pass = !pass; |
1681 | if(!pass) |
1682 | return false; |
1683 | break; |
1684 | } |
1685 | } |
1686 | } |
1687 | } |
1688 | } |
1689 | } else if(project->values(comp + ".CONFIG").indexOf( "verify") != -1) { |
1690 | QString tmp_out = project->values(comp + ".output").first(); |
1691 | if(tmp_out.isEmpty()) |
1692 | return false; |
1693 | QString tmp_cmd; |
1694 | if(!project->isEmpty(comp + ".commands")) { |
1695 | int argv0 = -1; |
1696 | QStringList cmdline = project->values(comp + ".commands"); |
1697 | for(int i = 0; i < cmdline.count(); ++i) { |
1698 | if(!cmdline.at(i).contains( |
1699 | argv0 = i; |
1700 | break; |
1701 | } |
1702 | } |
1703 | if(argv0 != -1) { |
1704 | cmdline[argv0] = Option::fixPathToTargetOS(cmdline.at(argv0), false); |
1705 | tmp_cmd = cmdline.join(" "); |
1706 | } |
1707 | } |
1708 | |
1709 | if(project->values(comp + ".CONFIG").indexOf( "combine") != -1) { |
1710 | QString cmd = replaceExtraCompilerVariables(tmp_cmd, QString(), tmp_out); |
1711 | if(system(cmd.toLatin1().constData())) |
1712 | return false; |
1713 | } else { |
1714 | QStringList &tmp = project->values(comp + ".input"); |
1715 | for(QStringList::Iterator it = tmp.begin(); it != tmp.end(); ++it) { |
1716 | QStringList &inputs = project->values((*it)); |
1717 | for(QStringList::Iterator input = inputs.begin(); input != inputs.end(); ++input) { |
1718 | if((*input).isEmpty()) |
1719 | continue; |
1720 | QString in = fileFixify(Option::fixPathToTargetOS((*input), false)); |
1721 | if(in == file) { |
1722 | QString out = replaceExtraCompilerVariables(tmp_out, (*input), QString()); |
1723 | QString cmd = replaceExtraCompilerVariables(tmp_cmd, in, out); |
1724 | if(system(cmd.toLatin1().constData())) |
1725 | return false; |
1726 | break; |
1727 | } |
1728 | } |
1729 | } |
1730 | } |
1731 | } |
1732 | return true; |
1733 | } |
1734 | |
1735 | void |
1736 | MakefileGenerator::writeExtraTargets(QTextStream &t) |
1737 | { |
1738 | QStringList &qut = project->values("QMAKE_EXTRA_TARGETS"); |
1739 | for(QStringList::Iterator it = qut.begin(); it != qut.end(); ++it) { |
1740 | QString targ = var((*it) + ".target"), |
1741 | cmd = var((*it) + ".commands"), deps; |
1742 | if(targ.isEmpty()) |
1743 | targ = (*it); |
1744 | QStringList &deplist = project->values((*it) + ".depends"); |
1745 | for(QStringList::Iterator dep_it = deplist.begin(); dep_it != deplist.end(); ++dep_it) { |
1746 | QString dep = var((*dep_it) + ".target"); |
1747 | if(dep.isEmpty()) |
1748 | dep = (*dep_it); |
1749 | deps += " "+ escapeDependencyPath(dep); |
1750 | } |
1751 | if(project->values((*it) + ".CONFIG").indexOf( "fix_target") != -1) |
1752 | targ = fileFixify(targ, Option::output_dir, Option::output_dir); |
1753 | if(project->isEmpty("QMAKE_NOFORCE") && |
1754 | project->values((*it) + ".CONFIG").indexOf( "phony") != -1) |
1755 | deps += QString(" ") + "FORCE"; |
1756 | t << escapeDependencyPath(targ) << ":"<< deps; |
1757 | if(!cmd.isEmpty()) |
1758 | t << "\n\t"<< cmd; |
1759 | t << endl << endl; |
1760 | |
1761 | project->values(QLatin1String("QMAKE_INTERNAL_ET_PARSED_TARGETS.") + (*it)) << escapeDependencyPath(targ); |
1762 | project->values(QLatin1String("QMAKE_INTERNAL_ET_PARSED_DEPS.") + (*it) + escapeDependencyPath(targ)) << deps.split( " ", QString::SkipEmptyParts); |
1763 | project->values(QLatin1String("QMAKE_INTERNAL_ET_PARSED_CMD.") + (*it) + escapeDependencyPath(targ)) << cmd; |
1764 | } |
1765 | } |
1766 | |
1767 | void |
1768 | MakefileGenerator::writeExtraCompilerTargets(QTextStream &t) |
1769 | { |
1770 | QString clean_targets; |
1771 | const QStringList &quc = project->values("QMAKE_EXTRA_COMPILERS"); |
1772 | QDir outputDir(Option::output_dir); |
1773 | for(QStringList::ConstIterator it = quc.begin(); it != quc.end(); ++it) { |
1774 | QString tmp_out = fileFixify(project->values((*it) + ".output").first(), |
1775 | Option::output_dir, Option::output_dir); |
1776 | QString tmp_cmd; |
1777 | if(!project->isEmpty((*it) + ".commands")) { |
1778 | QStringList cmdline = project->values((*it) + ".commands"); |
1779 | int argv0 = findExecutable(cmdline); |
1780 | if(argv0 != -1) { |
1781 | cmdline[argv0] = escapeFilePath(Option::fixPathToTargetOS(cmdline.at(argv0), false)); |
1782 | tmp_cmd = cmdline.join(" "); |
1783 | } |
1784 | } |
1785 | QStringList tmp_dep = project->values((*it) + ".depends"); |
1786 | QString tmp_dep_cmd; |
1787 | QString dep_cd_cmd; |
1788 | if(!project->isEmpty((*it) + ".depend_command")) { |
1789 | int argv0 = -1; |
1790 | QStringList cmdline = project->values((*it) + ".depend_command"); |
1791 | for(int i = 0; i < cmdline.count(); ++i) { |
1792 | if(!cmdline.at(i).contains( |
1793 | argv0 = i; |
1794 | break; |
1795 | } |
1796 | } |
1797 | if(argv0 != -1) { |
1798 | const QString c = Option::fixPathToLocalOS(cmdline.at(argv0), true); |
1799 | if(exists(c)) { |
1800 | cmdline[argv0] = escapeFilePath(Option::fixPathToLocalOS(cmdline.at(argv0), false)); |
1801 | } else { |
1802 | cmdline[argv0] = escapeFilePath(cmdline.at(argv0)); |
1803 | } |
1804 | QFileInfo cmdFileInfo(cmdline[argv0]); |
1805 | if (!cmdFileInfo.isAbsolute() || cmdFileInfo.exists()) |
1806 | tmp_dep_cmd = cmdline.join(" "); |
1807 | } |
1808 | dep_cd_cmd = QLatin1String("cd ") |
1809 | + escapeFilePath(Option::fixPathToLocalOS(Option::output_dir, false)) |
1810 | + QLatin1String(" && "); |
1811 | } |
1812 | QStringList &vars = project->values((*it) + ".variables"); |
1813 | if(tmp_out.isEmpty() || tmp_cmd.isEmpty()) |
1814 | continue; |
1815 | QStringList tmp_inputs; |
1816 | { |
1817 | const QStringList &comp_inputs = project->values((*it) + ".input"); |
1818 | for(QStringList::ConstIterator it2 = comp_inputs.begin(); it2 != comp_inputs.end(); ++it2) { |
1819 | const QStringList &tmp = project->values((*it2)); |
1820 | for(QStringList::ConstIterator input = tmp.begin(); input != tmp.end(); ++input) { |
1821 | QString in = Option::fixPathToTargetOS((*input), false); |
1822 | if(verifyExtraCompiler((*it), in)) |
1823 | tmp_inputs.append((*input)); |
1824 | } |
1825 | } |
1826 | } |
1827 | |
1828 | t << "compiler_"<< (*it) << "_make_all:"; |
1829 | if(project->values((*it) + ".CONFIG").indexOf( "combine") != -1) { |
1830 | // compilers with a combined input only have one output |
1831 | QString input = project->values((*it) + ".output").first(); |
1832 | t << " "<< escapeDependencyPath(replaceExtraCompilerVariables(tmp_out, input, QString())); |
1833 | } else { |
1834 | for(QStringList::ConstIterator input = tmp_inputs.begin(); input != tmp_inputs.end(); ++input) { |
1835 | QString in = Option::fixPathToTargetOS((*input), false); |
1836 | t << " "<< escapeDependencyPath(replaceExtraCompilerVariables(tmp_out, (*input), QString())); |
1837 | } |
1838 | } |
1839 | t << endl; |
1840 | |
1841 | if(project->values((*it) + ".CONFIG").indexOf( "no_clean") == -1) { |
1842 | QString tmp_clean = project->values((*it) + ".clean").join( " "); |
1843 | QString tmp_clean_cmds = project->values((*it) + ".clean_commands").join( " "); |
1844 | if(!tmp_inputs.isEmpty()) |
1845 | clean_targets += QString("compiler_"+ (*it) + "_clean "); |
1846 | t << "compiler_"<< (*it) << "_clean:"; |
1847 | bool wrote_clean_cmds = false, wrote_clean = false; |
1848 | if(tmp_clean_cmds.isEmpty()) { |
1849 | wrote_clean_cmds = true; |
1850 | } else if(tmp_clean_cmds.indexOf("${QMAKE_") == -1) { |
1851 | t << "\n\t"<< tmp_clean_cmds; |
1852 | wrote_clean_cmds = true; |
1853 | } |
1854 | if(tmp_clean.isEmpty()) |
1855 | tmp_clean = tmp_out; |
1856 | if(tmp_clean.indexOf("${QMAKE_") == -1) { |
1857 | t << "\n\t"<< "-$(DEL_FILE) "<< tmp_clean; |
1858 | wrote_clean = true; |
1859 | } |
1860 | if(!wrote_clean_cmds || !wrote_clean) { |
1861 | QStringList cleans; |
1862 | const QString del_statement("-$(DEL_FILE)"); |
1863 | if(!wrote_clean) { |
1864 | if(project->isActiveConfig("no_delete_multiple_files")) { |
1865 | for(QStringList::ConstIterator input = tmp_inputs.begin(); input != tmp_inputs.end(); ++input) |
1866 | cleans.append(" "+ replaceExtraCompilerVariables(tmp_clean, (*input), |
1867 | replaceExtraCompilerVariables(tmp_out, (*input), QString()))); |
1868 | } else { |
1869 | QString files, file; |
1870 | const int commandlineLimit = 2047; // NT limit, expanded |
1871 | for(int input = 0; input < tmp_inputs.size(); ++input) { |
1872 | file = " "+ replaceExtraCompilerVariables(tmp_clean, tmp_inputs.at(input), |
1873 | replaceExtraCompilerVariables(tmp_out, tmp_inputs.at(input), QString())); |
1874 | if(del_statement.length() + files.length() + |
1875 | qMax(fixEnvVariables(file).length(), file.length()) > commandlineLimit) { |
1876 | cleans.append(files); |
1877 | files.clear(); |
1878 | } |
1879 | files += file; |
1880 | } |
1881 | if(!files.isEmpty()) |
1882 | cleans.append(files); |
1883 | } |
1884 | } |
1885 | if(!cleans.isEmpty()) |
1886 | t << valGlue(cleans, "\n\t"+ del_statement, "\n\t"+ del_statement, ""); |
1887 | if(!wrote_clean_cmds) { |
1888 | for(QStringList::ConstIterator input = tmp_inputs.begin(); input != tmp_inputs.end(); ++input) { |
1889 | t << "\n\t"<< replaceExtraCompilerVariables(tmp_clean_cmds, (*input), |
1890 | replaceExtraCompilerVariables(tmp_out, (*input), QString())); |
1891 | } |
1892 | } |
1893 | } |
1894 | t << endl; |
1895 | } |
1896 | if(project->values((*it) + ".CONFIG").indexOf( "combine") != -1) { |
1897 | if(tmp_out.indexOf("${QMAKE_") != -1) { |
1898 | warn_msg(WarnLogic, "QMAKE_EXTRA_COMPILERS(%s) with combine has variable output.", |
1899 | (*it).toLatin1().constData()); |
1900 | continue; |
1901 | } |
1902 | QStringList deps, inputs; |
1903 | if(!tmp_dep.isEmpty()) |
1904 | deps += fileFixify(tmp_dep, Option::output_dir, Option::output_dir); |
1905 | for(QStringList::ConstIterator input = tmp_inputs.begin(); input != tmp_inputs.end(); ++input) { |
1906 | deps += findDependencies((*input)); |
1907 | inputs += Option::fixPathToTargetOS((*input), false); |
1908 | if(!tmp_dep_cmd.isEmpty() && doDepends()) { |
1909 | char buff[256]; |
1910 | QString dep_cmd = replaceExtraCompilerVariables(tmp_dep_cmd, (*input), |
1911 | tmp_out); |
1912 | dep_cmd = dep_cd_cmd + fixEnvVariables(dep_cmd); |
1913 | if(FILE *proc = QT_POPEN(dep_cmd.toLatin1().constData(), "r")) { |
1914 | QString indeps; |
1915 | while(!feof(proc)) { |
1916 | int read_in = (int)fread(buff, 1, 255, proc); |
1917 | if(!read_in) |
1918 | break; |
1919 | indeps += QByteArray(buff, read_in); |
1920 | } |
1921 | QT_PCLOSE(proc); |
1922 | if(!indeps.isEmpty()) { |
1923 | QStringList dep_cmd_deps = indeps.replace( |
1924 | for(int i = 0; i < dep_cmd_deps.count(); ++i) { |
1925 | QString &file = dep_cmd_deps[i]; |
1926 | if(!exists(file)) { |
1927 | QString localFile; |
1928 | QList<QMakeLocalFileName> depdirs = QMakeSourceFileInfo::dependencyPaths(); |
1929 | for(QList<QMakeLocalFileName>::Iterator it = depdirs.begin(); |
1930 | it != depdirs.end(); ++it) { |
1931 | if(exists((*it).real() + Option::dir_sep + file)) { |
1932 | localFile = (*it).local() + Option::dir_sep + file; |
1933 | break; |
1934 | } |
1935 | } |
1936 | file = localFile; |
1937 | } |
1938 | if(!file.isEmpty()) |
1939 | file = fileFixify(file); |
1940 | } |
1941 | deps += dep_cmd_deps; |
1942 | } |
1943 | } |
1944 | } |
1945 | } |
1946 | for(int i = 0; i < inputs.size(); ) { |
1947 | if(tmp_out == inputs.at(i)) |
1948 | inputs.removeAt(i); |
1949 | else |
1950 | ++i; |
1951 | } |
1952 | for(int i = 0; i < deps.size(); ) { |
1953 | if(tmp_out == deps.at(i)) |
1954 | deps.removeAt(i); |
1955 | else |
1956 | ++i; |
1957 | } |
1958 | if (inputs.isEmpty()) |
1959 | continue; |
1960 | |
1961 | QString cmd; |
1962 | if (isForSymbianSbsv2()) { |
1963 | // In sbsv2 the command inputs and outputs need to use absolute paths |
1964 | QStringList absoluteInputs; |
1965 | for (int i = 0; i < inputs.size(); ++i) |
1966 | absoluteInputs.append(escapeFilePath(outputDir.absoluteFilePath(inputs.at(i)))); |
1967 | cmd = replaceExtraCompilerVariables(tmp_cmd, absoluteInputs, |
1968 | QStringList(outputDir.absoluteFilePath(tmp_out))); |
1969 | } else { |
1970 | cmd = replaceExtraCompilerVariables(tmp_cmd, escapeFilePaths(inputs), QStringList(tmp_out)); |
1971 | } |
1972 | |
1973 | t << escapeDependencyPath(tmp_out) << ":"; |
1974 | project->values(QLatin1String("QMAKE_INTERNAL_ET_PARSED_TARGETS.") + (*it)) << escapeDependencyPath(tmp_out); |
1975 | // compiler.CONFIG+=explicit_dependencies means that ONLY compiler.depends gets to cause Makefile dependencies |
1976 | if(project->values((*it) + ".CONFIG").indexOf( "explicit_dependencies") != -1) { |
1977 | t << " "<< valList(escapeDependencyPaths(fileFixify(tmp_dep, Option::output_dir, Option::output_dir))); |
1978 | project->values(QLatin1String("QMAKE_INTERNAL_ET_PARSED_DEPS.") + (*it) + escapeDependencyPath(tmp_out)) << tmp_dep; |
1979 | } else { |
1980 | t << " "<< valList(escapeDependencyPaths(inputs)) << " "<< valList(escapeDependencyPaths(deps)); |
1981 | project->values(QLatin1String("QMAKE_INTERNAL_ET_PARSED_DEPS.") + (*it) + escapeDependencyPath(tmp_out)) << inputs << deps; |
1982 | } |
1983 | t << "\n\t"<< cmd << endl << endl; |
1984 | project->values(QLatin1String("QMAKE_INTERNAL_ET_PARSED_CMD.") + (*it) + escapeDependencyPath(tmp_out)) << cmd; |
1985 | continue; |
1986 | } |
1987 | for(QStringList::ConstIterator input = tmp_inputs.begin(); input != tmp_inputs.end(); ++input) { |
1988 | QString in = Option::fixPathToTargetOS((*input), false); |
1989 | QStringList deps = findDependencies((*input)); |
1990 | deps += escapeDependencyPath(in); |
1991 | QString out = unescapeFilePath(replaceExtraCompilerVariables(tmp_out, (*input), QString())); |
1992 | if(!tmp_dep.isEmpty()) { |
1993 | QStringList pre_deps = fileFixify(tmp_dep, Option::output_dir, Option::output_dir); |
1994 | for(int i = 0; i < pre_deps.size(); ++i) |
1995 | deps += replaceExtraCompilerVariables(pre_deps.at(i), (*input), out); |
1996 | } |
1997 | QString cmd = replaceExtraCompilerVariables(tmp_cmd, (*input), out); |
1998 | // NOTE: The var -> QMAKE_COMP_var replace feature is unsupported, do not use! |
1999 | if (isForSymbianSbsv2()) { |
2000 | // In sbsv2 the command inputs and outputs need to use absolute paths |
2001 | cmd = replaceExtraCompilerVariables(tmp_cmd, |
2002 | outputDir.absoluteFilePath(*input), |
2003 | outputDir.absoluteFilePath(out)); |
2004 | } else { |
2005 | cmd = replaceExtraCompilerVariables(tmp_cmd, (*input), out); |
2006 | } |
2007 | for(QStringList::ConstIterator it3 = vars.constBegin(); it3 != vars.constEnd(); ++it3) |
2008 | cmd.replace("$("+ (*it3) + ")", "$(QMAKE_COMP_"+ (*it3)+ ")"); |
2009 | if(!tmp_dep_cmd.isEmpty() && doDepends()) { |
2010 | char buff[256]; |
2011 | QString dep_cmd = replaceExtraCompilerVariables(tmp_dep_cmd, (*input), out); |
2012 | dep_cmd = dep_cd_cmd + fixEnvVariables(dep_cmd); |
2013 | if(FILE *proc = QT_POPEN(dep_cmd.toLatin1().constData(), "r")) { |
2014 | QString indeps; |
2015 | while(!feof(proc)) { |
2016 | int read_in = (int)fread(buff, 1, 255, proc); |
2017 | if(!read_in) |
2018 | break; |
2019 | indeps += QByteArray(buff, read_in); |
2020 | } |
2021 | QT_PCLOSE(proc); |
2022 | if(!indeps.isEmpty()) { |
2023 | QStringList dep_cmd_deps = indeps.replace( |
2024 | for(int i = 0; i < dep_cmd_deps.count(); ++i) { |
2025 | QString &file = dep_cmd_deps[i]; |
2026 | if(!exists(file)) { |
2027 | QString localFile; |
2028 | QList<QMakeLocalFileName> depdirs = QMakeSourceFileInfo::dependencyPaths(); |
2029 | for(QList<QMakeLocalFileName>::Iterator it = depdirs.begin(); |
2030 | it != depdirs.end(); ++it) { |
2031 | if(exists((*it).real() + Option::dir_sep + file)) { |
2032 | localFile = (*it).local() + Option::dir_sep + file; |
2033 | break; |
2034 | } |
2035 | } |
2036 | file = localFile; |
2037 | } |
2038 | if(!file.isEmpty()) |
2039 | file = fileFixify(file); |
2040 | } |
2041 | deps += dep_cmd_deps; |
2042 | } |
2043 | } |
2044 | //use the depend system to find includes of these included files |
2045 | QStringList inc_deps; |
2046 | for(int i = 0; i < deps.size(); ++i) { |
2047 | const QString dep = deps.at(i); |
2048 | if(QFile::exists(dep)) { |
2049 | SourceFileType type = TYPE_UNKNOWN; |
2050 | if(type == TYPE_UNKNOWN) { |
2051 | for(QStringList::Iterator cit = Option::c_ext.begin(); |
2052 | cit != Option::c_ext.end(); ++cit) { |
2053 | if(dep.endsWith((*cit))) { |
2054 | type = TYPE_C; |
2055 | break; |
2056 | } |
2057 | } |
2058 | } |
2059 | if(type == TYPE_UNKNOWN) { |
2060 | for(QStringList::Iterator cppit = Option::cpp_ext.begin(); |
2061 | cppit != Option::cpp_ext.end(); ++cppit) { |
2062 | if(dep.endsWith((*cppit))) { |
2063 | type = TYPE_C; |
2064 | break; |
2065 | } |
2066 | } |
2067 | } |
2068 | if(type == TYPE_UNKNOWN) { |
2069 | for(QStringList::Iterator hit = Option::h_ext.begin(); |
2070 | type == TYPE_UNKNOWN && hit != Option::h_ext.end(); ++hit) { |
2071 | if(dep.endsWith((*hit))) { |
2072 | type = TYPE_C; |
2073 | break; |
2074 | } |
2075 | } |
2076 | } |
2077 | if(type != TYPE_UNKNOWN) { |
2078 | if(!QMakeSourceFileInfo::containsSourceFile(dep, type)) |
2079 | QMakeSourceFileInfo::addSourceFile(dep, type); |
2080 | inc_deps += QMakeSourceFileInfo::dependencies(dep); |
2081 | } |
2082 | } |
2083 | } |
2084 | deps += inc_deps; |
2085 | } |
2086 | for(int i = 0; i < deps.size(); ) { |
2087 | QString &dep = deps[i]; |
2088 | dep = Option::fixPathToTargetOS(unescapeFilePath(dep), false); |
2089 | if(out == dep) |
2090 | deps.removeAt(i); |
2091 | else |
2092 | ++i; |
2093 | } |
2094 | t << escapeDependencyPath(out) << ": "<< valList(escapeDependencyPaths(deps)) << "\n\t" |
2095 | << cmd << endl << endl; |
2096 | project->values(QLatin1String("QMAKE_INTERNAL_ET_PARSED_TARGETS.") + (*it)) << escapeDependencyPath(out); |
2097 | project->values(QLatin1String("QMAKE_INTERNAL_ET_PARSED_DEPS.") + (*it) + escapeDependencyPath(out)) << deps; |
2098 | project->values(QLatin1String("QMAKE_INTERNAL_ET_PARSED_CMD.") + (*it) + escapeDependencyPath(out)) << cmd; |
2099 | } |
2100 | } |
2101 | t << "compiler_clean: "<< clean_targets << endl << endl; |
2102 | } |
2103 | |
2104 | void |
2105 | MakefileGenerator::writeExtraCompilerVariables(QTextStream &t) |
2106 | { |
2107 | bool first = true; |
2108 | const QStringList &quc = project->values("QMAKE_EXTRA_COMPILERS"); |
2109 | for(QStringList::ConstIterator it = quc.begin(); it != quc.end(); ++it) { |
2110 | const QStringList &vars = project->values((*it) + ".variables"); |
2111 | for(QStringList::ConstIterator varit = vars.begin(); varit != vars.end(); ++varit) { |
2112 | if(first) { |
2113 | t << "\n####### Custom Compiler Variables"<< endl; |
2114 | first = false; |
2115 | } |
2116 | t << "QMAKE_COMP_"<< (*varit) << " = " |
2117 | << valList(project->values((*varit))) << endl; |
2118 | } |
2119 | } |
2120 | if(!first) |
2121 | t << endl; |
2122 | } |
2123 | |
2124 | void |
2125 | MakefileGenerator::writeExtraVariables(QTextStream &t) |
2126 | { |
2127 | bool first = true; |
2128 | QMap<QString, QStringList> &vars = project->variables(); |
2129 | QStringList &exports = project->values("QMAKE_EXTRA_VARIABLES"); |
2130 | for(QMap<QString, QStringList>::Iterator it = vars.begin(); it != vars.end(); ++it) { |
2131 | for(QStringList::Iterator exp_it = exports.begin(); exp_it != exports.end(); ++exp_it) { |
2132 | QRegExp rx((*exp_it), Qt::CaseInsensitive, QRegExp::Wildcard); |
2133 | if(rx.exactMatch(it.key())) { |
2134 | if(first) { |
2135 | t << "\n####### Custom Variables"<< endl; |
2136 | first = false; |
2137 | } |
2138 | t << "EXPORT_"<< it.key() << " = "<< it.value().join( " ") << endl; |
2139 | } |
2140 | } |
2141 | } |
2142 | if(!first) |
2143 | t << endl; |
2144 | } |
2145 | |
2146 | bool |
2147 | MakefileGenerator::writeStubMakefile(QTextStream &t) |
2148 | { |
2149 | t << "QMAKE = "<< var( "QMAKE_QMAKE") << endl; |
2150 | QStringList &qut = project->values("QMAKE_EXTRA_TARGETS"); |
2151 | for(QStringList::ConstIterator it = qut.begin(); it != qut.end(); ++it) |
2152 | t << *it << " "; |
2153 | //const QString ofile = Option::fixPathToTargetOS(fileFixify(Option::output.fileName())); |
2154 | t << "first all clean install distclean uninstall: "<< "qmake"<< endl |
2155 | << "qmake_all:"<< endl; |
2156 | writeMakeQmake(t); |
2157 | if(project->isEmpty("QMAKE_NOFORCE")) |
2158 | t << "FORCE:"<< endl << endl; |
2159 | return true; |
2160 | } |
2161 | |
2162 | bool |
2163 | MakefileGenerator::writeMakefile(QTextStream &t) |
2164 | { |
2165 | t << "####### Compile"<< endl << endl; |
2166 | writeObj(t, "SOURCES"); |
2167 | writeObj(t, "GENERATED_SOURCES"); |
2168 | |
2169 | t << "####### Install"<< endl << endl; |
2170 | writeInstalls(t, "INSTALLS"); |
2171 | |
2172 | if(project->isEmpty("QMAKE_NOFORCE")) |
2173 | t << "FORCE:"<< endl << endl; |
2174 | return true; |
2175 | } |
2176 | |
2177 | QString MakefileGenerator::buildArgs(const QString &outdir) |
2178 | { |
2179 | QString ret; |
2180 | //special variables |
2181 | if(!project->isEmpty("QMAKE_ABSOLUTE_SOURCE_PATH")) |
2182 | ret += " QMAKE_ABSOLUTE_SOURCE_PATH="+ escapeFilePath(project->first( "QMAKE_ABSOLUTE_SOURCE_PATH")); |
2183 | |
2184 | //warnings |
2185 | else if(Option::warn_level == WarnNone) |
2186 | ret += " -Wnone"; |
2187 | else if(Option::warn_level == WarnAll) |
2188 | ret += " -Wall"; |
2189 | else if(Option::warn_level & WarnParser) |
2190 | ret += " -Wparser"; |
2191 | //other options |
2192 | if(!Option::user_template.isEmpty()) |
2193 | ret += " -t "+ Option::user_template; |
2194 | if(!Option::user_template_prefix.isEmpty()) |
2195 | ret += " -tp "+ Option::user_template_prefix; |
2196 | if(!Option::mkfile::do_cache) |
2197 | ret += " -nocache"; |
2198 | if(!Option::mkfile::do_deps) |
2199 | ret += " -nodepend"; |
2200 | if(!Option::mkfile::do_dep_heuristics) |
2201 | ret += " -nodependheuristics"; |
2202 | if(!Option::mkfile::qmakespec_commandline.isEmpty()) |
2203 | ret += " -spec "+ specdir(outdir); |
2204 | if (Option::target_mode_overridden) { |
2205 | if (Option::target_mode == Option::TARG_MACX_MODE) |
2206 | ret += " -macx"; |
2207 | else if (Option::target_mode == Option::TARG_UNIX_MODE) |
2208 | ret += " -unix"; |
2209 | else if (Option::target_mode == Option::TARG_WIN_MODE) |
2210 | ret += " -win32"; |
2211 | } |
2212 | |
2213 | //configs |
2214 | for(QStringList::Iterator it = Option::user_configs.begin(); |
2215 | it != Option::user_configs.end(); ++it) |
2216 | ret += " -config "+ (*it); |
2217 | //arguments |
2218 | for(QStringList::Iterator it = Option::before_user_vars.begin(); |
2219 | it != Option::before_user_vars.end(); ++it) { |
2220 | if((*it).left(qstrlen("QMAKE_ABSOLUTE_SOURCE_PATH")) != "QMAKE_ABSOLUTE_SOURCE_PATH") |
2221 | ret += " "+ escapeFilePath((*it)); |
2222 | } |
2223 | if(Option::after_user_vars.count()) { |
2224 | ret += " -after "; |
2225 | for(QStringList::Iterator it = Option::after_user_vars.begin(); |
2226 | it != Option::after_user_vars.end(); ++it) { |
2227 | if((*it).left(qstrlen("QMAKE_ABSOLUTE_SOURCE_PATH")) != "QMAKE_ABSOLUTE_SOURCE_PATH") |
2228 | ret += " "+ escapeFilePath((*it)); |
2229 | } |
2230 | } |
2231 | return ret; |
2232 | } |
2233 | |
2234 | //could get stored argv, but then it would have more options than are |
2235 | //probably necesary this will try to guess the bare minimum.. |
2236 | QString MakefileGenerator::build_args(const QString &outdir) |
2237 | { |
2238 | QString ret = "$(QMAKE)"; |
2239 | |
2240 | // general options and arguments |
2241 | ret += buildArgs(outdir); |
2242 | |
2243 | //output |
2244 | QString ofile = Option::fixPathToTargetOS(fileFixify(Option::output.fileName())); |
2245 | if(!ofile.isEmpty() && ofile != project->first("QMAKE_MAKEFILE")) |
2246 | ret += " -o "+ escapeFilePath(ofile); |
2247 | |
2248 | //inputs |
2249 | ret += " "+ escapeFilePath(fileFixify(project->projectFile(), outdir)); |
2250 | |
2251 | return ret; |
2252 | } |
2253 | |
2254 | void |
2255 | MakefileGenerator::writeHeader(QTextStream &t) |
2256 | { |
2257 | t << "#############################################################################"<< endl; |
2258 | t << "# Makefile for building: "<< escapeFilePath(var( "TARGET")) << endl; |
2259 | t << "# Generated by qmake ("<< qmake_version() << ") (Qt "<< QT_VERSION_STR << ") on: "; |
2260 | t << QDateTime::currentDateTime().toString() << endl; |
2261 | t << "# Project: "<< fileFixify(project->projectFile()) << endl; |
2262 | t << "# Template: "<< var( "TEMPLATE") << endl; |
2263 | if(!project->isActiveConfig("build_pass")) |
2264 | t << "# Command: "<< build_args().replace( "$(QMAKE)", var( "QMAKE_QMAKE")) << endl; |
2265 | t << "#############################################################################"<< endl; |
2266 | t << endl; |
2267 | } |
2268 | |
2269 | QList<MakefileGenerator::SubTarget*> |
2270 | MakefileGenerator::findSubDirsSubTargets() const |
2271 | { |
2272 | QList<SubTarget*> targets; |
2273 | { |
2274 | const QStringList subdirs = project->values("SUBDIRS"); |
2275 | for(int subdir = 0; subdir < subdirs.size(); ++subdir) { |
2276 | QString fixedSubdir = subdirs[subdir]; |
2277 | fixedSubdir = fixedSubdir.replace(QRegExp("[^a-zA-Z0-9_]"), "-"); |
2278 | |
2279 | SubTarget *st = new SubTarget; |
2280 | st->name = subdirs[subdir]; |
2281 | targets.append(st); |
2282 | |
2283 | bool fromFile = false; |
2284 | QString file = subdirs[subdir]; |
2285 | if(!project->isEmpty(fixedSubdir + ".file")) { |
2286 | if(!project->isEmpty(fixedSubdir + ".subdir")) |
2287 | warn_msg(WarnLogic, "Cannot assign both file and subdir for subdir %s", |
2288 | subdirs[subdir].toLatin1().constData()); |
2289 | file = project->first(fixedSubdir + ".file"); |
2290 | fromFile = true; |
2291 | } else if(!project->isEmpty(fixedSubdir + ".subdir")) { |
2292 | file = project->first(fixedSubdir + ".subdir"); |
2293 | fromFile = false; |
2294 | } else { |
2295 | fromFile = file.endsWith(Option::pro_ext); |
2296 | } |
2297 | file = Option::fixPathToTargetOS(file); |
2298 | |
2299 | if(fromFile) { |
2300 | int slsh = file.lastIndexOf(Option::dir_sep); |
2301 | if(slsh != -1) { |
2302 | st->in_directory = file.left(slsh+1); |
2303 | st->profile = file.mid(slsh+1); |
2304 | } else { |
2305 | st->profile = file; |
2306 | } |
2307 | } else { |
2308 | if(!file.isEmpty() && !project->isActiveConfig("subdir_first_pro")) |
2309 | st->profile = file.section(Option::dir_sep, -1) + Option::pro_ext; |
2310 | st->in_directory = file; |
2311 | } |
2312 | while(st->in_directory.endsWith(Option::dir_sep)) |
2313 | st->in_directory.chop(1); |
2314 | if(fileInfo(st->in_directory).isRelative()) |
2315 | st->out_directory = st->in_directory; |
2316 | else |
2317 | st->out_directory = fileFixify(st->in_directory, qmake_getpwd(), Option::output_dir); |
2318 | if(!project->isEmpty(fixedSubdir + ".makefile")) { |
2319 | st->makefile = project->first(fixedSubdir + ".makefile"); |
2320 | } else { |
2321 | st->makefile = "$(MAKEFILE)"; |
2322 | if(!st->profile.isEmpty()) { |
2323 | QString basename = st->in_directory; |
2324 | int new_slsh = basename.lastIndexOf(Option::dir_sep); |
2325 | if(new_slsh != -1) |
2326 | basename = basename.mid(new_slsh+1); |
2327 | if(st->profile != basename + Option::pro_ext) |
2328 | st->makefile += "."+ st->profile.left(st->profile.length() - Option::pro_ext.length()); |
2329 | } |
2330 | } |
2331 | if(!project->isEmpty(fixedSubdir + ".depends")) { |
2332 | const QStringList depends = project->values(fixedSubdir + ".depends"); |
2333 | for(int depend = 0; depend < depends.size(); ++depend) { |
2334 | bool found = false; |
2335 | for(int subDep = 0; subDep < subdirs.size(); ++subDep) { |
2336 | if(subdirs[subDep] == depends.at(depend)) { |
2337 | QString fixedSubDep = subdirs[subDep]; |
2338 | fixedSubDep = fixedSubDep.replace(QRegExp("[^a-zA-Z0-9_]"), "-"); |
2339 | if(!project->isEmpty(fixedSubDep + ".target")) { |
2340 | st->depends += project->first(fixedSubDep + ".target"); |
2341 | } else { |
2342 | QString d = Option::fixPathToLocalOS(subdirs[subDep]); |
2343 | if(!project->isEmpty(fixedSubDep + ".file")) |
2344 | d = project->first(fixedSubDep + ".file"); |
2345 | else if(!project->isEmpty(fixedSubDep + ".subdir")) |
2346 | d = project->first(fixedSubDep + ".subdir"); |
2347 | st->depends += "sub-"+ d.replace(QRegExp( "[^a-zA-Z0-9_]"), "-"); |
2348 | } |
2349 | found = true; |
2350 | break; |
2351 | } |
2352 | } |
2353 | if(!found) { |
2354 | QString depend_str = depends.at(depend); |
2355 | st->depends += depend_str.replace(QRegExp("[^a-zA-Z0-9_]"), "-"); |
2356 | } |
2357 | } |
2358 | } |
2359 | if(!project->isEmpty(fixedSubdir + ".target")) { |
2360 | st->target = project->first(fixedSubdir + ".target"); |
2361 | } else { |
2362 | st->target = "sub-"+ file; |
2363 | st->target = st->target.replace(QRegExp("[^a-zA-Z0-9_]"), "-"); |
2364 | } |
2365 | } |
2366 | } |
2367 | return targets; |
2368 | } |
2369 | |
2370 | void |
2371 | MakefileGenerator::writeSubDirs(QTextStream &t) |
2372 | { |
2373 | QList<SubTarget*> targets = findSubDirsSubTargets(); |
2374 | t << "first: make_default"<< endl; |
2375 | int flags = SubTargetInstalls; |
2376 | if(project->isActiveConfig("ordered")) |
2377 | flags |= SubTargetOrdered; |
2378 | writeSubTargets(t, targets, flags); |
2379 | qDeleteAll(targets); |
2380 | } |
2381 | |
2382 | void MakefileGenerator::writeSubMakeCall(QTextStream &t, const QString &callPrefix, |
2383 | const QString &makeArguments, const QString &callPostfix) |
2384 | { |
2385 | t << callPrefix |
2386 | << "$(MAKE)"<< makeArguments |
2387 | << callPostfix << endl; |
2388 | } |
2389 | |
2390 | void |
2391 | MakefileGenerator::writeSubTargets(QTextStream &t, QList<MakefileGenerator::SubTarget*> targets, int flags) |
2392 | { |
2393 | // blasted includes |
2394 | QStringList &qeui = project->values("QMAKE_EXTRA_INCLUDES"); |
2395 | for(QStringList::Iterator qeui_it = qeui.begin(); qeui_it != qeui.end(); ++qeui_it) |
2396 | t << "include "<< (*qeui_it) << endl; |
2397 | |
2398 | if (!(flags & SubTargetSkipDefaultVariables)) { |
2399 | QString ofile = Option::fixPathToTargetOS(Option::output.fileName()); |
2400 | if(ofile.lastIndexOf(Option::dir_sep) != -1) |
2401 | ofile.remove(0, ofile.lastIndexOf(Option::dir_sep) +1); |
2402 | t << "MAKEFILE = "<< ofile << endl; |
2403 | /* Calling Option::fixPathToTargetOS() is necessary for MinGW/MSYS, which requires |
2404 | * back-slashes to be turned into slashes. */ |
2405 | t << "QMAKE = "<< var( "QMAKE_QMAKE") << endl; |
2406 | t << "DEL_FILE = "<< var( "QMAKE_DEL_FILE") << endl; |
2407 | t << "CHK_DIR_EXISTS= "<< var( "QMAKE_CHK_DIR_EXISTS") << endl; |
2408 | t << "MKDIR = "<< var( "QMAKE_MKDIR") << endl; |
2409 | t << "COPY = "<< var( "QMAKE_COPY") << endl; |
2410 | t << "COPY_FILE = "<< var( "QMAKE_COPY_FILE") << endl; |
2411 | t << "COPY_DIR = "<< var( "QMAKE_COPY_DIR") << endl; |
2412 | t << "INSTALL_FILE = "<< var( "QMAKE_INSTALL_FILE") << endl; |
2413 | t << "INSTALL_PROGRAM = "<< var( "QMAKE_INSTALL_PROGRAM") << endl; |
2414 | t << "INSTALL_DIR = "<< var( "QMAKE_INSTALL_DIR") << endl; |
2415 | t << "DEL_FILE = "<< var( "QMAKE_DEL_FILE") << endl; |
2416 | t << "SYMLINK = "<< var( "QMAKE_SYMBOLIC_LINK") << endl; |
2417 | t << "DEL_DIR = "<< var( "QMAKE_DEL_DIR") << endl; |
2418 | t << "MOVE = "<< var( "QMAKE_MOVE") << endl; |
2419 | t << "CHK_DIR_EXISTS= "<< var( "QMAKE_CHK_DIR_EXISTS") << endl; |
2420 | t << "MKDIR = "<< var( "QMAKE_MKDIR") << endl; |
2421 | t << "SUBTARGETS = "; // subtargets are sub-directory |
2422 | for(int target = 0; target < targets.size(); ++target) |
2423 | t << " \\\n\t\t"<< targets.at(target)->target; |
2424 | t << endl << endl; |
2425 | } |
2426 | writeExtraVariables(t); |
2427 | |
2428 | QStringList targetSuffixes; |
2429 | const QString abs_source_path = project->first("QMAKE_ABSOLUTE_SOURCE_PATH"); |
2430 | if (!(flags & SubTargetSkipDefaultTargets)) { |
2431 | targetSuffixes << "make_default"<< "make_first"<< "all"<< "clean"<< "distclean" |
2432 | << QString((flags & SubTargetInstalls) ? "install_subtargets": "install") |
2433 | << QString((flags & SubTargetInstalls) ? "uninstall_subtargets": "uninstall"); |
2434 | } |
2435 | |
2436 | // generate target rules |
2437 | for(int target = 0; target < targets.size(); ++target) { |
2438 | SubTarget *subtarget = targets.at(target); |
2439 | QString in_directory = subtarget->in_directory; |
2440 | if(!in_directory.isEmpty() && !in_directory.endsWith(Option::dir_sep)) |
2441 | in_directory += Option::dir_sep; |
2442 | QString out_directory = subtarget->out_directory; |
2443 | if(!out_directory.isEmpty() && !out_directory.endsWith(Option::dir_sep)) |
2444 | out_directory += Option::dir_sep; |
2445 | if(!abs_source_path.isEmpty() && out_directory.startsWith(abs_source_path)) |
2446 | out_directory = Option::output_dir + out_directory.mid(abs_source_path.length()); |
2447 | |
2448 | QString mkfile = subtarget->makefile; |
2449 | if(!in_directory.isEmpty()) |
2450 | mkfile.prepend(out_directory); |
2451 | |
2452 | QString in_directory_cdin, in_directory_cdout, out_directory_cdin, out_directory_cdout; |
2453 | #define MAKE_CD_IN_AND_OUT(directory) \ |
2454 | if(!directory.isEmpty()) { \ |
2455 | if(project->isActiveConfig("cd_change_global")) { \ |
2456 | directory ## _cdin = "\n\tcd " + directory + "\n\t"; \ |
2457 | QDir pwd(Option::output_dir); \ |
2458 | QStringList in = directory.split(Option::dir_sep), out; \ |
2459 | for(int i = 0; i < in.size(); i++) { \ |
2460 | if(in.at(i) == "..") \ |
2461 | out.prepend(fileInfo(pwd.path()).fileName()); \ |
2462 | else if(in.at(i) != ".") \ |
2463 | out.prepend(".."); \ |
2464 | pwd.cd(in.at(i)); \ |
2465 | } \ |
2466 | directory ## _cdout = "\n\t@cd " + out.join(Option::dir_sep); \ |
2467 | } else { \ |
2468 | directory ## _cdin = "\n\tcd " + directory + " && "; \ |
2469 | } \ |
2470 | } else { \ |
2471 | directory ## _cdin = "\n\t"; \ |
2472 | } |
2473 | MAKE_CD_IN_AND_OUT(in_directory); |
2474 | MAKE_CD_IN_AND_OUT(out_directory); |
2475 | |
2476 | //qmake it |
2477 | if(!subtarget->profile.isEmpty()) { |
2478 | QString out = subtarget->makefile; |
2479 | QString in = escapeFilePath(fileFixify(in_directory + subtarget->profile, FileFixifyAbsolute)); |
2480 | if(out.startsWith(in_directory)) |
2481 | out = out.mid(in_directory.length()); |
2482 | t << mkfile << ": "<< "\n\t"; |
2483 | if(!in_directory.isEmpty()) { |
2484 | t << mkdir_p_asstring(out_directory) |
2485 | << out_directory_cdin |
2486 | << "$(QMAKE) "<< in << buildArgs(in_directory) << " -o "<< out |
2487 | << in_directory_cdout << endl; |
2488 | } else { |
2489 | t << "$(QMAKE) "<< in << buildArgs(in_directory) << " -o "<< out << endl; |
2490 | } |
2491 | t << subtarget->target << "-qmake_all: "; |
2492 | if(project->isEmpty("QMAKE_NOFORCE")) |
2493 | t << " FORCE"; |
2494 | t << "\n\t"; |
2495 | if(!in_directory.isEmpty()) { |
2496 | t << mkdir_p_asstring(out_directory) |
2497 | << out_directory_cdin |
2498 | << "$(QMAKE) "<< in << buildArgs(in_directory) << " -o "<< out |
2499 | << in_directory_cdout << endl; |
2500 | } else { |
2501 | t << "$(QMAKE) "<< in << buildArgs(in_directory) << " -o "<< out << endl; |
2502 | } |
2503 | } |
2504 | |
2505 | QString makefilein = " -f "+ subtarget->makefile; |
2506 | |
2507 | { //actually compile |
2508 | t << subtarget->target << ": "<< mkfile; |
2509 | if(!subtarget->depends.isEmpty()) |
2510 | t << " "<< valList(subtarget->depends); |
2511 | if(project->isEmpty("QMAKE_NOFORCE")) |
2512 | t << " FORCE"; |
2513 | writeSubMakeCall(t, out_directory_cdin, makefilein, out_directory_cdout); |
2514 | } |
2515 | |
2516 | for(int suffix = 0; suffix < targetSuffixes.size(); ++suffix) { |
2517 | QString s = targetSuffixes.at(suffix); |
2518 | if(s == "install_subtargets") |
2519 | s = "install"; |
2520 | else if(s == "uninstall_subtargets") |
2521 | s = "uninstall"; |
2522 | else if(s == "make_first") |
2523 | s = "first"; |
2524 | else if(s == "make_default") |
2525 | s = QString(); |
2526 | |
2527 | if(flags & SubTargetOrdered) { |
2528 | t << subtarget->target << "-"<< targetSuffixes.at(suffix) << "-ordered: "<< mkfile; |
2529 | if(target) |
2530 | t << " "<< targets.at(target-1)->target << "-"<< targetSuffixes.at(suffix) << "-ordered "; |
2531 | if(project->isEmpty("QMAKE_NOFORCE")) |
2532 | t << " FORCE"; |
2533 | writeSubMakeCall(t, out_directory_cdin, makefilein + " "+ s, out_directory_cdout); |
2534 | } |
2535 | t << subtarget->target << "-"<< targetSuffixes.at(suffix) << ": "<< mkfile; |
2536 | if(!subtarget->depends.isEmpty()) |
2537 | t << " "<< valGlue(subtarget->depends, QString(), "-"+ targetSuffixes.at(suffix) + " ", |
2538 | "-"+targetSuffixes.at(suffix)); |
2539 | if(project->isEmpty("QMAKE_NOFORCE")) |
2540 | t << " FORCE"; |
2541 | writeSubMakeCall(t, out_directory_cdin, makefilein + " "+ s, out_directory_cdout); |
2542 | } |
2543 | } |
2544 | t << endl; |
2545 | |
2546 | if (!(flags & SubTargetSkipDefaultTargets)) { |
2547 | if(project->values("QMAKE_INTERNAL_QMAKE_DEPS").indexOf( "qmake_all") == -1) |
2548 | project->values("QMAKE_INTERNAL_QMAKE_DEPS").append( "qmake_all"); |
2549 | |
2550 | writeMakeQmake(t); |
2551 | |
2552 | t << "qmake_all:"; |
2553 | if(!targets.isEmpty()) { |
2554 | for(QList<SubTarget*>::Iterator it = targets.begin(); it != targets.end(); ++it) { |
2555 | if(!(*it)->profile.isEmpty()) |
2556 | t << " "<< (*it)->target << "-"<< "qmake_all"; |
2557 | } |
2558 | } |
2559 | if(project->isEmpty("QMAKE_NOFORCE")) |
2560 | t << " FORCE"; |
2561 | if(project->isActiveConfig("no_empty_targets")) |
2562 | t << "\n\t"<< "@cd ."; |
2563 | t << endl << endl; |
2564 | } |
2565 | |
2566 | for(int s = 0; s < targetSuffixes.size(); ++s) { |
2567 | QString suffix = targetSuffixes.at(s); |
2568 | if(!(flags & SubTargetInstalls) && suffix.endsWith("install")) |
2569 | continue; |
2570 | |
2571 | t << suffix << ":"; |
2572 | for(int target = 0; target < targets.size(); ++target) { |
2573 | SubTarget *subTarget = targets.at(target); |
2574 | if((suffix == "make_first"|| suffix == "make_default") |
2575 | && project->values(subTarget->name + ".CONFIG").indexOf( "no_default_target") != -1) { |
2576 | continue; |
2577 | } |
2578 | QString targetRule = subTarget->target + "-"+ suffix; |
2579 | if(flags & SubTargetOrdered) |
2580 | targetRule += "-ordered"; |
2581 | t << " "<< targetRule; |
2582 | } |
2583 | if(suffix == "all"|| suffix == "make_first") |
2584 | t << varGlue("ALL_DEPS", " ", " ", ""); |
2585 | if(suffix == "clean") |
2586 | t << varGlue("CLEAN_DEPS", " ", " ", ""); |
2587 | if(project->isEmpty("QMAKE_NOFORCE")) |
2588 | t << " FORCE"; |
2589 | t << endl; |
2590 | if(suffix == "clean") { |
2591 | t << varGlue("QMAKE_CLEAN", "\t-$(DEL_FILE) ", "\n\t-$(DEL_FILE) ", "\n"); |
2592 | } else if(suffix == "distclean") { |
2593 | QString ofile = Option::fixPathToTargetOS(fileFixify(Option::output.fileName())); |
2594 | if(!ofile.isEmpty()) |
2595 | t << "\t-$(DEL_FILE) "<< ofile << endl; |
2596 | t << varGlue("QMAKE_DISTCLEAN", "\t-$(DEL_FILE) ", " ", "\n"); |
2597 | } else if(project->isActiveConfig("no_empty_targets")) { |
2598 | t << "\t"<< "@cd ."<< endl; |
2599 | } |
2600 | } |
2601 | |
2602 | // user defined targets |
2603 | QStringList &qut = project->values("QMAKE_EXTRA_TARGETS"); |
2604 | for(QStringList::Iterator qut_it = qut.begin(); qut_it != qut.end(); ++qut_it) { |
2605 | QString targ = var((*qut_it) + ".target"), |
2606 | cmd = var((*qut_it) + ".commands"), deps; |
2607 | if(targ.isEmpty()) |
2608 | targ = (*qut_it); |
2609 | t << endl; |
2610 | |
2611 | QStringList &deplist = project->values((*qut_it) + ".depends"); |
2612 | for(QStringList::Iterator dep_it = deplist.begin(); dep_it != deplist.end(); ++dep_it) { |
2613 | QString dep = var((*dep_it) + ".target"); |
2614 | if(dep.isEmpty()) |
2615 | dep = Option::fixPathToTargetOS(*dep_it, false); |
2616 | deps += " "+ dep; |
2617 | } |
2618 | if(project->values((*qut_it) + ".CONFIG").indexOf( "recursive") != -1) { |
2619 | QSet<QString> recurse; |
2620 | if(project->isSet((*qut_it) + ".recurse")) { |
2621 | recurse = project->values((*qut_it) + ".recurse").toSet(); |
2622 | } else { |
2623 | for(int target = 0; target < targets.size(); ++target) |
2624 | recurse.insert(targets.at(target)->name); |
2625 | } |
2626 | for(int target = 0; target < targets.size(); ++target) { |
2627 | SubTarget *subtarget = targets.at(target); |
2628 | QString in_directory = subtarget->in_directory; |
2629 | if(!in_directory.isEmpty() && !in_directory.endsWith(Option::dir_sep)) |
2630 | in_directory += Option::dir_sep; |
2631 | QString out_directory = subtarget->out_directory; |
2632 | if(!out_directory.isEmpty() && !out_directory.endsWith(Option::dir_sep)) |
2633 | out_directory += Option::dir_sep; |
2634 | if(!abs_source_path.isEmpty() && out_directory.startsWith(abs_source_path)) |
2635 | out_directory = Option::output_dir + out_directory.mid(abs_source_path.length()); |
2636 | |
2637 | if(!recurse.contains(subtarget->name)) |
2638 | continue; |
2639 | QString mkfile = subtarget->makefile; |
2640 | if(!in_directory.isEmpty()) { |
2641 | if(!out_directory.endsWith(Option::dir_sep)) |
2642 | mkfile.prepend(out_directory + Option::dir_sep); |
2643 | else |
2644 | mkfile.prepend(out_directory); |
2645 | } |
2646 | QString out_directory_cdin, out_directory_cdout; |
2647 | MAKE_CD_IN_AND_OUT(out_directory); |
2648 | |
2649 | QString makefilein = " -f "+ subtarget->makefile; |
2650 | |
2651 | //write the rule/depends |
2652 | if(flags & SubTargetOrdered) { |
2653 | const QString dep = subtarget->target + "-"+ (*qut_it) + "_ordered"; |
2654 | t << dep << ": "<< mkfile; |
2655 | if(target) |
2656 | t << " "<< targets.at(target-1)->target << "-"<< (*qut_it) << "_ordered "; |
2657 | deps += " "+ dep; |
2658 | } else { |
2659 | const QString dep = subtarget->target + "-"+ (*qut_it); |
2660 | t << dep << ": "<< mkfile; |
2661 | if(!subtarget->depends.isEmpty()) |
2662 | t << " "<< valGlue(subtarget->depends, QString(), "-"+ (*qut_it) + " ", "-"+ (*qut_it)); |
2663 | deps += " "+ dep; |
2664 | } |
2665 | |
2666 | QString sub_targ = targ; |
2667 | if(project->isSet((*qut_it) + ".recurse_target")) |
2668 | sub_targ = project->first((*qut_it) + ".recurse_target"); |
2669 | |
2670 | //write the commands |
2671 | if(!out_directory.isEmpty()) { |
2672 | writeSubMakeCall(t, out_directory_cdin, makefilein + " "+ sub_targ, |
2673 | out_directory_cdout); |
2674 | } else { |
2675 | writeSubMakeCall(t, "\n\t", makefilein + " "+ sub_targ, QString()); |
2676 | } |
2677 | } |
2678 | } |
2679 | if(project->isEmpty("QMAKE_NOFORCE") && |
2680 | project->values((*qut_it) + ".CONFIG").indexOf( "phony") != -1) |
2681 | deps += " FORCE"; |
2682 | t << targ << ":"<< deps << "\n"; |
2683 | if(!cmd.isEmpty()) |
2684 | t << "\t"<< cmd << endl; |
2685 | } |
2686 | |
2687 | if(flags & SubTargetInstalls) { |
2688 | project->values("INSTALLDEPS") += "install_subtargets"; |
2689 | project->values("UNINSTALLDEPS") += "uninstall_subtargets"; |
2690 | writeInstalls(t, "INSTALLS", true); |
2691 | } |
2692 | |
2693 | if(project->isEmpty("QMAKE_NOFORCE")) |
2694 | t << "FORCE:"<< endl << endl; |
2695 | } |
2696 | |
2697 | void |
2698 | MakefileGenerator::writeMakeQmake(QTextStream &t) |
2699 | { |
2700 | QString ofile = Option::fixPathToTargetOS(fileFixify(Option::output.fileName())); |
2701 | if(project->isEmpty("QMAKE_FAILED_REQUIREMENTS") && !project->isEmpty( "QMAKE_INTERNAL_PRL_FILE")) { |
2702 | QStringList files = fileFixify(Option::mkfile::project_files); |
2703 | t << escapeDependencyPath(project->first("QMAKE_INTERNAL_PRL_FILE")) << ": "<< "\n\t" |
2704 | << "@$(QMAKE) -prl "<< buildArgs() << " "<< files.join( " ") << endl; |
2705 | } |
2706 | |
2707 | QString pfile = project->projectFile(); |
2708 | if(pfile != "(stdin)") { |
2709 | QString qmake = build_args(); |
2710 | if(!ofile.isEmpty() && !project->isActiveConfig("no_autoqmake")) { |
2711 | t << escapeFilePath(ofile) << ": "<< escapeDependencyPath(fileFixify(pfile)) << " "; |
2712 | if(Option::mkfile::do_cache) |
2713 | t << escapeDependencyPath(fileFixify(Option::mkfile::cachefile)) << " "; |
2714 | if(!specdir().isEmpty()) { |
2715 | if(exists(Option::fixPathToLocalOS(specdir()+QDir::separator()+"qmake.conf"))) |
2716 | t << escapeDependencyPath(specdir() + Option::dir_sep + "qmake.conf") << " "; |
2717 | } |
2718 | const QStringList &included = project->values("QMAKE_INTERNAL_INCLUDED_FILES"); |
2719 | t << escapeDependencyPaths(included).join(" \\\n\t\t") << "\n\t" |
2720 | << qmake << endl; |
2721 | for(int include = 0; include < included.size(); ++include) { |
2722 | const QString i(included.at(include)); |
2723 | if(!i.isEmpty()) |
2724 | t << i << ":"<< endl; |
2725 | } |
2726 | } |
2727 | if(project->first("QMAKE_ORIG_TARGET") != "qmake") { |
2728 | t << "qmake: "<< |
2729 | project->values("QMAKE_INTERNAL_QMAKE_DEPS").join( " \\\n\t\t"); |
2730 | if(project->isEmpty("QMAKE_NOFORCE")) |
2731 | t << " FORCE"; |
2732 | t << "\n\t"<< "@"<< qmake << endl << endl; |
2733 | } |
2734 | } |
2735 | } |
2736 | |
2737 | QFileInfo |
2738 | MakefileGenerator::fileInfo(QString file) const |
2739 | { |
2740 | static QHash<FileInfoCacheKey, QFileInfo> *cache = 0; |
2741 | static QFileInfo noInfo = QFileInfo(); |
2742 | if(!cache) { |
2743 | cache = new QHash<FileInfoCacheKey, QFileInfo>; |
2744 | qmakeAddCacheClear(qmakeDeleteCacheClear<QHash<FileInfoCacheKey, QFileInfo> >, (void**)&cache); |
2745 | } |
2746 | FileInfoCacheKey cacheKey(file); |
2747 | QFileInfo value = cache->value(cacheKey, noInfo); |
2748 | if (value != noInfo) |
2749 | return value; |
2750 | |
2751 | QFileInfo fi(file); |
2752 | if (fi.exists()) |
2753 | cache->insert(cacheKey, fi); |
2754 | return fi; |
2755 | } |
2756 | |
2757 | QString |
2758 | MakefileGenerator::unescapeFilePath(const QString &path) const |
2759 | { |
2760 | QString ret = path; |
2761 | if(!ret.isEmpty()) { |
2762 | if(ret.contains(QLatin1String("\\ "))) |
2763 | ret.replace(QLatin1String("\\ "), QLatin1String( " ")); |
2764 | if(ret.contains(QLatin1Char( |
2765 | ret.remove(QLatin1Char( |
2766 | } |
2767 | return ret; |
2768 | } |
2769 | |
2770 | QStringList |
2771 | MakefileGenerator::escapeFilePaths(const QStringList &paths) const |
2772 | { |
2773 | QStringList ret; |
2774 | for(int i = 0; i < paths.size(); ++i) |
2775 | ret.append(escapeFilePath(paths.at(i))); |
2776 | return ret; |
2777 | } |
2778 | |
2779 | QStringList |
2780 | MakefileGenerator::escapeDependencyPaths(const QStringList &paths) const |
2781 | { |
2782 | QStringList ret; |
2783 | for(int i = 0; i < paths.size(); ++i) |
2784 | ret.append(escapeDependencyPath(paths.at(i))); |
2785 | return ret; |
2786 | } |
2787 | |
2788 | QStringList |
2789 | MakefileGenerator::unescapeFilePaths(const QStringList &paths) const |
2790 | { |
2791 | QStringList ret; |
2792 | for(int i = 0; i < paths.size(); ++i) |
2793 | ret.append(unescapeFilePath(paths.at(i))); |
2794 | return ret; |
2795 | } |
2796 | |
2797 | QStringList |
2798 | MakefileGenerator::fileFixify(const QStringList& files, const QString &out_dir, const QString &in_dir, |
2799 | FileFixifyType fix, bool canon) const |
2800 | { |
2801 | if(files.isEmpty()) |
2802 | return files; |
2803 | QStringList ret; |
2804 | for(QStringList::ConstIterator it = files.begin(); it != files.end(); ++it) { |
2805 | if(!(*it).isEmpty()) |
2806 | ret << fileFixify((*it), out_dir, in_dir, fix, canon); |
2807 | } |
2808 | return ret; |
2809 | } |
2810 | |
2811 | QString |
2812 | MakefileGenerator::fileFixify(const QString& file, const QString &out_d, const QString &in_d, |
2813 | FileFixifyType fix, bool canon) const |
2814 | { |
2815 | if(file.isEmpty()) |
2816 | return file; |
2817 | QString ret = unescapeFilePath(file); |
2818 | |
2819 | //do the fixin' |
2820 | QString orig_file = ret; |
2821 | if(ret.startsWith(QLatin1Char( |
2822 | if(ret.startsWith(QLatin1String("~/"))) |
2823 | ret = QDir::homePath() + ret.mid(1); |
2824 | else |
2825 | warn_msg(WarnLogic, "Unable to expand ~ in %s", ret.toLatin1().constData()); |
2826 | } |
2827 | if(fix == FileFixifyAbsolute || (fix == FileFixifyDefault && project->isActiveConfig("no_fixpath"))) { |
2828 | if(fix == FileFixifyAbsolute && QDir::isRelativePath(ret)) { //already absolute |
2829 | QString pwd = qmake_getpwd(); |
2830 | if (!pwd.endsWith(QLatin1Char( |
2831 | pwd += QLatin1Char( |
2832 | ret.prepend(pwd); |
2833 | } |
2834 | ret = Option::fixPathToTargetOS(ret, false, canon); |
2835 | } else { //fix it.. |
2836 | QString out_dir = QDir(Option::output_dir).absoluteFilePath(out_d); |
2837 | QString in_dir = QDir(qmake_getpwd()).absoluteFilePath(in_d); |
2838 | { |
2839 | QFileInfo in_fi(fileInfo(in_dir)); |
2840 | if(in_fi.exists()) |
2841 | in_dir = in_fi.canonicalFilePath(); |
2842 | QFileInfo out_fi(fileInfo(out_dir)); |
2843 | if(out_fi.exists()) |
2844 | out_dir = out_fi.canonicalFilePath(); |
2845 | } |
2846 | |
2847 | QString qfile(Option::fixPathToLocalOS(ret, true, canon)); |
2848 | QFileInfo qfileinfo(fileInfo(qfile)); |
2849 | if(out_dir != in_dir || !qfileinfo.isRelative()) { |
2850 | if(qfileinfo.isRelative()) { |
2851 | ret = in_dir + "/"+ qfile; |
2852 | qfileinfo.setFile(ret); |
2853 | } |
2854 | ret = Option::fixPathToTargetOS(ret, false, canon); |
2855 | if(canon && qfileinfo.exists() && |
2856 | file == Option::fixPathToTargetOS(ret, true, canon)) |
2857 | ret = Option::fixPathToTargetOS(qfileinfo.canonicalFilePath()); |
2858 | QString match_dir = Option::fixPathToTargetOS(out_dir, false, canon); |
2859 | if(ret == match_dir) { |
2860 | ret = ""; |
2861 | } else if(ret.startsWith(match_dir + Option::dir_sep)) { |
2862 | ret = ret.mid(match_dir.length() + Option::dir_sep.length()); |
2863 | } else { |
2864 | //figure out the depth |
2865 | int depth = 4; |
2866 | if(Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE || |
2867 | Option::qmake_mode == Option::QMAKE_GENERATE_PRL) { |
2868 | if(project && !project->isEmpty("QMAKE_PROJECT_DEPTH")) |
2869 | depth = project->first("QMAKE_PROJECT_DEPTH").toInt(); |
2870 | else if(Option::mkfile::cachefile_depth != -1) |
2871 | depth = Option::mkfile::cachefile_depth; |
2872 | } |
2873 | //calculate how much can be removed |
2874 | QString dot_prefix; |
2875 | for(int i = 1; i <= depth; i++) { |
2876 | int sl = match_dir.lastIndexOf(Option::dir_sep); |
2877 | if(sl == -1) |
2878 | break; |
2879 | match_dir = match_dir.left(sl); |
2880 | if(match_dir.isEmpty()) |
2881 | break; |
2882 | if(ret.startsWith(match_dir + Option::dir_sep)) { |
2883 | //concat |
2884 | int remlen = ret.length() - (match_dir.length() + 1); |
2885 | if(remlen < 0) |
2886 | remlen = 0; |
2887 | ret = ret.right(remlen); |
2888 | //prepend |
2889 | for(int o = 0; o < i; o++) |
2890 | dot_prefix += ".."+ Option::dir_sep; |
2891 | break; |
2892 | } |
2893 | } |
2894 | ret.prepend(dot_prefix); |
2895 | } |
2896 | } else { |
2897 | ret = Option::fixPathToTargetOS(ret, false, canon); |
2898 | } |
2899 | } |
2900 | if(ret.isEmpty()) |
2901 | ret = "."; |
2902 | debug_msg(3, "Fixed[%d,%d] %s :: to :: %s [%s::%s] [%s::%s]", fix, canon, orig_file.toLatin1().constData(), |
2903 | ret.toLatin1().constData(), in_d.toLatin1().constData(), out_d.toLatin1().constData(), |
2904 | qmake_getpwd().toLatin1().constData(), Option::output_dir.toLatin1().constData()); |
2905 | return ret; |
2906 | } |
2907 | |
2908 | void |
2909 | MakefileGenerator::checkMultipleDefinition(const QString &f, const QString &w) |
2910 | { |
2911 | if(!(Option::warn_level & WarnLogic)) |
2912 | return; |
2913 | QString file = f; |
2914 | int slsh = f.lastIndexOf(Option::dir_sep); |
2915 | if(slsh != -1) |
2916 | file.remove(0, slsh + 1); |
2917 | QStringList &l = project->values(w); |
2918 | for(QStringList::Iterator val_it = l.begin(); val_it != l.end(); ++val_it) { |
2919 | QString file2((*val_it)); |
2920 | slsh = file2.lastIndexOf(Option::dir_sep); |
2921 | if(slsh != -1) |
2922 | file2.remove(0, slsh + 1); |
2923 | if(file2 == file) { |
2924 | warn_msg(WarnLogic, "Found potential symbol conflict of %s (%s) in %s", |
2925 | file.toLatin1().constData(), (*val_it).toLatin1().constData(), w.toLatin1().constData()); |
2926 | break; |
2927 | } |
2928 | } |
2929 | } |
2930 | |
2931 | QMakeLocalFileName |
2932 | MakefileGenerator::fixPathForFile(const QMakeLocalFileName &file, bool forOpen) |
2933 | { |
2934 | if(forOpen) |
2935 | return QMakeLocalFileName(fileFixify(file.real(), qmake_getpwd(), Option::output_dir)); |
2936 | return QMakeLocalFileName(fileFixify(file.real())); |
2937 | } |
2938 | |
2939 | QFileInfo |
2940 | MakefileGenerator::findFileInfo(const QMakeLocalFileName &file) |
2941 | { |
2942 | return fileInfo(file.local()); |
2943 | } |
2944 | |
2945 | QMakeLocalFileName |
2946 | MakefileGenerator::findFileForDep(const QMakeLocalFileName &dep, const QMakeLocalFileName &file) |
2947 | { |
2948 | QMakeLocalFileName ret; |
2949 | if(!project->isEmpty("SKIP_DEPENDS")) { |
2950 | bool found = false; |
2951 | QStringList &nodeplist = project->values("SKIP_DEPENDS"); |
2952 | for(QStringList::Iterator it = nodeplist.begin(); |
2953 | it != nodeplist.end(); ++it) { |
2954 | QRegExp regx((*it)); |
2955 | if(regx.indexIn(dep.local()) != -1) { |
2956 | found = true; |
2957 | break; |
2958 | } |
2959 | } |
2960 | if(found) |
2961 | return ret; |
2962 | } |
2963 | |
2964 | ret = QMakeSourceFileInfo::findFileForDep(dep, file); |
2965 | if(!ret.isNull()) |
2966 | return ret; |
2967 | |
2968 | //these are some "hacky" heuristics it will try to do on an include |
2969 | //however these can be turned off at runtime, I'm not sure how |
2970 | //reliable these will be, most likely when problems arise turn it off |
2971 | //and see if they go away.. |
2972 | if(Option::mkfile::do_dep_heuristics) { |
2973 | if(depHeuristicsCache.contains(dep.real())) |
2974 | return depHeuristicsCache[dep.real()]; |
2975 | |
2976 | if(Option::output_dir != qmake_getpwd() |
2977 | && QDir::isRelativePath(dep.real())) { //is it from the shadow tree |
2978 | QList<QMakeLocalFileName> depdirs = QMakeSourceFileInfo::dependencyPaths(); |
2979 | depdirs.prepend(fileInfo(file.real()).absoluteDir().path()); |
2980 | QString pwd = qmake_getpwd(); |
2981 | if(pwd.at(pwd.length()-1) != |
2982 | pwd += |
2983 | for(int i = 0; i < depdirs.count(); i++) { |
2984 | QString dir = depdirs.at(i).real(); |
2985 | if(!QDir::isRelativePath(dir) && dir.startsWith(pwd)) |
2986 | dir = dir.mid(pwd.length()); |
2987 | if(QDir::isRelativePath(dir)) { |
2988 | if(!dir.endsWith(Option::dir_sep)) |
2989 | dir += Option::dir_sep; |
2990 | QString shadow = fileFixify(dir + dep.local(), pwd, Option::output_dir); |
2991 | if(exists(shadow)) { |
2992 | ret = QMakeLocalFileName(shadow); |
2993 | goto found_dep_from_heuristic; |
2994 | } |
2995 | } |
2996 | } |
2997 | } |
2998 | { //is it from an EXTRA_TARGET |
2999 | const QString dep_basename = dep.local().section(Option::dir_sep, -1); |
3000 | QStringList &qut = project->values("QMAKE_EXTRA_TARGETS"); |
3001 | for(QStringList::Iterator it = qut.begin(); it != qut.end(); ++it) { |
3002 | QString targ = var((*it) + ".target"); |
3003 | if(targ.isEmpty()) |
3004 | targ = (*it); |
3005 | QString out = Option::fixPathToTargetOS(targ); |
3006 | if(out == dep.real() || out.section(Option::dir_sep, -1) == dep_basename) { |
3007 | ret = QMakeLocalFileName(out); |
3008 | goto found_dep_from_heuristic; |
3009 | } |
3010 | } |
3011 | } |
3012 | { //is it from an EXTRA_COMPILER |
3013 | const QString dep_basename = dep.local().section(Option::dir_sep, -1); |
3014 | const QStringList &quc = project->values("QMAKE_EXTRA_COMPILERS"); |
3015 | for(QStringList::ConstIterator it = quc.begin(); it != quc.end(); ++it) { |
3016 | QString tmp_out = project->values((*it) + ".output").first(); |
3017 | if(tmp_out.isEmpty()) |
3018 | continue; |
3019 | QStringList &tmp = project->values((*it) + ".input"); |
3020 | for(QStringList::Iterator it2 = tmp.begin(); it2 != tmp.end(); ++it2) { |
3021 | QStringList &inputs = project->values((*it2)); |
3022 | for(QStringList::Iterator input = inputs.begin(); input != inputs.end(); ++input) { |
3023 | QString out = Option::fixPathToTargetOS(unescapeFilePath(replaceExtraCompilerVariables(tmp_out, (*input), QString()))); |
3024 | if(out == dep.real() || out.section(Option::dir_sep, -1) == dep_basename) { |
3025 | ret = QMakeLocalFileName(fileFixify(out, qmake_getpwd(), Option::output_dir)); |
3026 | goto found_dep_from_heuristic; |
3027 | } |
3028 | } |
3029 | } |
3030 | } |
3031 | } |
3032 | found_dep_from_heuristic: |
3033 | depHeuristicsCache.insert(dep.real(), ret); |
3034 | } |
3035 | return ret; |
3036 | } |
3037 | |
3038 | QStringList |
3039 | &MakefileGenerator::findDependencies(const QString &file) |
3040 | { |
3041 | const QString fixedFile = fileFixify(file); |
3042 | if(!dependsCache.contains(fixedFile)) { |
3043 | #if 1 |
3044 | QStringList deps = QMakeSourceFileInfo::dependencies(file); |
3045 | if(file != fixedFile) |
3046 | deps += QMakeSourceFileInfo::dependencies(fixedFile); |
3047 | #else |
3048 | QStringList deps = QMakeSourceFileInfo::dependencies(fixedFile); |
3049 | #endif |
3050 | dependsCache.insert(fixedFile, deps); |
3051 | } |
3052 | return dependsCache[fixedFile]; |
3053 | } |
3054 | |
3055 | QString |
3056 | MakefileGenerator::specdir(const QString &outdir) |
3057 | { |
3058 | #if 0 |
3059 | if(!spec.isEmpty()) |
3060 | return spec; |
3061 | #endif |
3062 | spec = fileFixify(Option::mkfile::qmakespec, outdir); |
3063 | return spec; |
3064 | } |
3065 | |
3066 | bool |
3067 | MakefileGenerator::openOutput(QFile &file, const QString &build) const |
3068 | { |
3069 | { |
3070 | QString outdir; |
3071 | if(!file.fileName().isEmpty()) { |
3072 | if(QDir::isRelativePath(file.fileName())) |
3073 | file.setFileName(Option::output_dir + "/"+ file.fileName()); //pwd when qmake was run |
3074 | QFileInfo fi(fileInfo(file.fileName())); |
3075 | if(fi.isDir()) |
3076 | outdir = file.fileName() + |
3077 | } |
3078 | if(!outdir.isEmpty() || file.fileName().isEmpty()) { |
3079 | QString fname = "Makefile"; |
3080 | if(!project->isEmpty("MAKEFILE")) |
3081 | fname = project->first("MAKEFILE"); |
3082 | file.setFileName(outdir + fname); |
3083 | } |
3084 | } |
3085 | if(QDir::isRelativePath(file.fileName())) { |
3086 | QString fname = Option::output_dir; //pwd when qmake was run |
3087 | if(!fname.endsWith("/")) |
3088 | fname += "/"; |
3089 | fname += file.fileName(); |
3090 | file.setFileName(fname); |
3091 | } |
3092 | if(!build.isEmpty()) |
3093 | file.setFileName(file.fileName() + "."+ build); |
3094 | if(project->isEmpty("QMAKE_MAKEFILE")) |
3095 | project->values("QMAKE_MAKEFILE").append(file.fileName()); |
3096 | int slsh = file.fileName().lastIndexOf( |
3097 | if(slsh != -1) |
3098 | mkdir(file.fileName().left(slsh)); |
3099 | if(file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) { |
3100 | QFileInfo fi(fileInfo(Option::output.fileName())); |
3101 | QString od; |
3102 | if(fi.isSymLink()) |
3103 | od = fileInfo(fi.readLink()).absolutePath(); |
3104 | else |
3105 | od = fi.path(); |
3106 | od = QDir::fromNativeSeparators(od); |
3107 | if(QDir::isRelativePath(od)) { |
3108 | QString dir = Option::output_dir; |
3109 | if (!dir.endsWith( |
3110 | dir += |
3111 | od.prepend(dir); |
3112 | } |
3113 | Option::output_dir = od; |
3114 | return true; |
3115 | } |
3116 | return false; |
3117 | } |
3118 | |
3119 | QString |
3120 | MakefileGenerator::pkgConfigFileName(bool fixify) |
3121 | { |
3122 | QString ret = var("TARGET"); |
3123 | int slsh = ret.lastIndexOf(Option::dir_sep); |
3124 | if(slsh != -1) |
3125 | ret = ret.right(ret.length() - slsh - 1); |
3126 | if(ret.startsWith("lib")) |
3127 | ret = ret.mid(3); |
3128 | int dot = ret.indexOf( |
3129 | if(dot != -1) |
3130 | ret = ret.left(dot); |
3131 | ret += Option::pkgcfg_ext; |
3132 | QString subdir = project->first("QMAKE_PKGCONFIG_DESTDIR"); |
3133 | if(!subdir.isEmpty()) { |
3134 | // initOutPaths() appends dir_sep, but just to be safe.. |
3135 | if (!subdir.endsWith(Option::dir_sep)) |
3136 | ret.prepend(Option::dir_sep); |
3137 | ret.prepend(subdir); |
3138 | } |
3139 | if(fixify) { |
3140 | if(QDir::isRelativePath(ret) && !project->isEmpty("DESTDIR")) |
3141 | ret.prepend(project->first("DESTDIR")); |
3142 | ret = Option::fixPathToLocalOS(fileFixify(ret, qmake_getpwd(), Option::output_dir)); |
3143 | } |
3144 | return ret; |
3145 | } |
3146 | |
3147 | QString |
3148 | MakefileGenerator::pkgConfigPrefix() const |
3149 | { |
3150 | if(!project->isEmpty("QMAKE_PKGCONFIG_PREFIX")) |
3151 | return project->first("QMAKE_PKGCONFIG_PREFIX"); |
3152 | return QLibraryInfo::location(QLibraryInfo::PrefixPath); |
3153 | } |
3154 | |
3155 | QString |
3156 | MakefileGenerator::pkgConfigFixPath(QString path) const |
3157 | { |
3158 | QString prefix = pkgConfigPrefix(); |
3159 | if(path.startsWith(prefix)) |
3160 | path = path.replace(prefix, "${prefix}"); |
3161 | return path; |
3162 | } |
3163 | |
3164 | void |
3165 | MakefileGenerator::writePkgConfigFile() |
3166 | { |
3167 | QString fname = pkgConfigFileName(), lname = fname; |
3168 | mkdir(fileInfo(fname).path()); |
3169 | int slsh = lname.lastIndexOf(Option::dir_sep); |
3170 | if(slsh != -1) |
3171 | lname = lname.right(lname.length() - slsh - 1); |
3172 | QFile ft(fname); |
3173 | if(!ft.open(QIODevice::WriteOnly)) |
3174 | return; |
3175 | project->values("ALL_DEPS").append(fileFixify(fname)); |
3176 | QTextStream t(&ft); |
3177 | |
3178 | QString prefix = pkgConfigPrefix(); |
3179 | QString libDir = project->first("QMAKE_PKGCONFIG_LIBDIR"); |
3180 | if(libDir.isEmpty()) |
3181 | libDir = prefix + Option::dir_sep + "lib"+ Option::dir_sep; |
3182 | QString includeDir = project->first("QMAKE_PKGCONFIG_INCDIR"); |
3183 | if(includeDir.isEmpty()) |
3184 | includeDir = prefix + "/include"; |
3185 | |
3186 | t << "prefix="<< prefix << endl; |
3187 | t << "exec_prefix=${prefix}\n" |
3188 | << "libdir="<< pkgConfigFixPath(libDir) << "\n" |
3189 | << "includedir="<< pkgConfigFixPath(includeDir) << endl; |
3190 | // non-standard entry. Provides useful info normally only |
3191 | // contained in the internal .qmake.cache file |
3192 | t << varGlue("CONFIG", "qt_config=", " ", "") << endl; |
3193 | |
3194 | //extra PKGCONFIG variables |
3195 | const QStringList &pkgconfig_vars = project->values("QMAKE_PKGCONFIG_VARIABLES"); |
3196 | for(int i = 0; i < pkgconfig_vars.size(); ++i) { |
3197 | QString var = project->first(pkgconfig_vars.at(i) + ".name"), |
3198 | val = project->values(pkgconfig_vars.at(i) + ".value").join( " "); |
3199 | if(var.isEmpty()) |
3200 | continue; |
3201 | if(val.isEmpty()) { |
3202 | const QStringList &var_vars = project->values(pkgconfig_vars.at(i) + ".variable"); |
3203 | for(int v = 0; v < var_vars.size(); ++v) { |
3204 | const QStringList &vars = project->values(var_vars.at(v)); |
3205 | for(int var = 0; var < vars.size(); ++var) { |
3206 | if(!val.isEmpty()) |
3207 | val += " "; |
3208 | val += pkgConfigFixPath(vars.at(var)); |
3209 | } |
3210 | } |
3211 | } |
3212 | t << var << "="<< val << endl; |
3213 | } |
3214 | |
3215 | t << endl; |
3216 | |
3217 | QString name = project->first("QMAKE_PKGCONFIG_NAME"); |
3218 | if(name.isEmpty()) { |
3219 | name = project->first("QMAKE_ORIG_TARGET").toLower(); |
3220 | name.replace(0, 1, name[0].toUpper()); |
3221 | } |
3222 | t << "Name: "<< name << endl; |
3223 | QString desc = project->values("QMAKE_PKGCONFIG_DESCRIPTION").join( " "); |
3224 | if(desc.isEmpty()) { |
3225 | if(name.isEmpty()) { |
3226 | desc = project->first("QMAKE_ORIG_TARGET").toLower(); |
3227 | desc.replace(0, 1, desc[0].toUpper()); |
3228 | } else { |
3229 | desc = name; |
3230 | } |
3231 | if(project->first("TEMPLATE") == "lib") { |
3232 | if(project->isActiveConfig("plugin")) |
3233 | desc += " Plugin"; |
3234 | else |
3235 | desc += " Library"; |
3236 | } else if(project->first("TEMPLATE") == "app") { |
3237 | desc += " Application"; |
3238 | } |
3239 | } |
3240 | t << "Description: "<< desc << endl; |
3241 | t << "Version: "<< project->first( "VERSION") << endl; |
3242 | |
3243 | // libs |
3244 | t << "Libs: "; |
3245 | QString pkgConfiglibDir; |
3246 | QString pkgConfiglibName; |
3247 | if (Option::target_mode == Option::TARG_MACX_MODE && project->isActiveConfig("lib_bundle")) { |
3248 | pkgConfiglibDir = "-F${libdir}"; |
3249 | QString bundle; |
3250 | if (!project->isEmpty("QMAKE_FRAMEWORK_BUNDLE_NAME")) |
3251 | bundle = unescapeFilePath(project->first("QMAKE_FRAMEWORK_BUNDLE_NAME")); |
3252 | else |
3253 | bundle = unescapeFilePath(project->first("TARGET")); |
3254 | int suffix = bundle.lastIndexOf(".framework"); |
3255 | if (suffix != -1) |
3256 | bundle = bundle.left(suffix); |
3257 | pkgConfiglibName = "-framework "+ bundle + " "; |
3258 | } else { |
3259 | pkgConfiglibDir = "-L${libdir}"; |
3260 | pkgConfiglibName = "-l"+ lname.left(lname.length()-Option::libtool_ext.length()); |
3261 | if (project->isActiveConfig("shared")) |
3262 | pkgConfiglibName += project->first("TARGET_VERSION_EXT"); |
3263 | } |
3264 | t << pkgConfiglibDir << " "<< pkgConfiglibName << " "<< endl; |
3265 | |
3266 | QStringList libs; |
3267 | if(!project->isEmpty("QMAKE_INTERNAL_PRL_LIBS")) { |
3268 | libs = project->values("QMAKE_INTERNAL_PRL_LIBS"); |
3269 | } else { |
3270 | libs << "QMAKE_LIBS"; //obvious one |
3271 | } |
3272 | libs << "QMAKE_LIBS_PRIVATE"; |
3273 | libs << "QMAKE_LFLAGS_THREAD"; //not sure about this one, but what about things like -pthread? |
3274 | t << "Libs.private: "; |
3275 | for(QStringList::ConstIterator it = libs.begin(); it != libs.end(); ++it) { |
3276 | t << project->values((*it)).join(" ") << " "; |
3277 | } |
3278 | t << endl; |
3279 | |
3280 | // flags |
3281 | // ### too many |
3282 | t << "Cflags: " |
3283 | // << var("QMAKE_CXXFLAGS") << " " |
3284 | << varGlue("PRL_EXPORT_DEFINES", "-D", " -D", " ") |
3285 | << project->values("PRL_EXPORT_CXXFLAGS").join( " ") |
3286 | << project->values("QMAKE_PKGCONFIG_CFLAGS").join( " ") |
3287 | // << varGlue("DEFINES","-D"," -D"," ") |
3288 | << " -I${includedir}"<< endl; |
3289 | |
3290 | // requires |
3291 | const QString requires = project->values("QMAKE_PKGCONFIG_REQUIRES").join( " "); |
3292 | if (!requires.isEmpty()) { |
3293 | t << "Requires: "<< requires << endl; |
3294 | } |
3295 | |
3296 | t << endl; |
3297 | } |
3298 | |
3299 | QT_END_NAMESPACE |
3300 |
Warning: That file was not part of the compilation database. It may have many parsing errors.