source: trunk/qmake/generators/os2/gnumake.cpp@ 289

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

qmake: Make sure that QMAKE_PRL_VERSION is ignored and not appended to the library name when reading .prl files of static libraries.

File size: 27.6 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the qmake application of the Qt Toolkit.
7**
8** Copyright (C) 2009 netlabs.org. OS/2 parts.
9**
10** $QT_BEGIN_LICENSE:LGPL$
11** Commercial Usage
12** Licensees holding valid Qt Commercial licenses may use this file in
13** accordance with the Qt Commercial License Agreement provided with the
14** Software or, alternatively, in accordance with the terms contained in
15** a written agreement between you and Nokia.
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, Nokia gives you certain
26** additional rights. These rights are described in the Nokia Qt LGPL
27** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
28** package.
29**
30** GNU General Public License Usage
31** Alternatively, this file may be used under the terms of the GNU
32** General Public License version 3.0 as published by the Free Software
33** Foundation and appearing in the file LICENSE.GPL included in the
34** packaging of this file. Please review the following information to
35** ensure the GNU General Public License version 3.0 requirements will be
36** met: http://www.gnu.org/copyleft/gpl.html.
37**
38** If you are unsure which license is appropriate for your use, please
39** contact the sales department at [email protected].
40** $QT_END_LICENSE$
41**
42****************************************************************************/
43
44#include "gnumake.h"
45#include "option.h"
46#include "meta.h"
47#include <qregexp.h>
48#include <qdir.h>
49#include <stdlib.h>
50#include <time.h>
51
52QT_BEGIN_NAMESPACE
53
54GNUMakefileGenerator::GNUMakefileGenerator() : Win32MakefileGenerator(), init_flag(false)
55{
56 if (isDosLikeShell())
57 quote = "\"";
58 else
59 quote = "'";
60}
61
62bool GNUMakefileGenerator::isDosLikeShell() const
63{
64#ifdef Q_OS_OS2
65 return Option::shellPath.isEmpty();
66#else
67 return Win32MakefileGenerator::isDosLikeShell();
68#endif
69}
70
71QString GNUMakefileGenerator::escapeFilePath(const QString &path) const
72{
73 QString ret = path;
74 if (!isDosLikeShell()) {
75 ret.remove('\"');
76 ret.replace('\\', "/");
77 ret.replace(' ', "\\ ");
78 } else {
79 ret.replace(QRegExp("\""), "");
80 ret.replace(QRegExp("[\\\\/]$"), "");
81 if (ret.contains(QRegExp("[ +&;%]")))
82 ret = quote + ret + quote;
83 }
84 return ret;
85}
86
87QString GNUMakefileGenerator::escapeDependencyPath(const QString &path) const
88{
89 // dependency escaping is always done Unix-way since this is a requirement
90 // of GNU make which allows " and ' to be part of the file name.
91 // Note that if the string is a make variable reference, we don't eascape!
92 QString ret = path;
93 QString trimmed = path.trimmed();
94 if (!trimmed.startsWith("$(") || !trimmed.endsWith(")")) {
95 ret.remove('\"');
96 ret.replace(' ', "\\ ");
97 }
98 return ret;
99}
100
101QString
102GNUMakefileGenerator::findBestVersion(const QString &d, const QString &stem, const QString &ext)
103{
104 QString bd = Option::fixPathToLocalOS(d, true);
105 if(!exists(bd))
106 return QString();
107
108 QString dllStem = stem + QTDLL_POSTFIX;
109
110 QString versionOverride;
111 if(!project->values("QMAKE_" + stem.toUpper() + "_VERSION_OVERRIDE").isEmpty())
112 versionOverride = project->values("QMAKE_" + stem.toUpper() + "_VERSION_OVERRIDE").first();
113
114 if (project->isActiveConfig("link_prl")) {
115 QMakeMetaInfo libinfo;
116 QString libfile = QMakeMetaInfo::findLib(bd + Option::dir_sep + dllStem);
117 if (project->values("QMAKE_PRL_INTERNAL_FILES").contains(libfile)) {
118 // already processed, return emtpy string to discard this lib
119 return QString("");
120 }
121 if (libinfo.readLib(libfile)) {
122 project->values("QMAKE_PRL_INTERNAL_FILES") += libfile;
123 QString target = libinfo.first("QMAKE_PRL_TARGET");
124 if (target == project->first("TARGET")) {
125 // circular reference to ourselves, return emtpy string to discard this lib
126 return QString("");
127 }
128 if (target.isEmpty())
129 target = dllStem;
130 if (!versionOverride.isEmpty())
131 target += versionOverride;
132 else if (!libinfo.values("QMAKE_PRL_CONFIG").contains("staticlib") &&
133 !libinfo.isEmpty("QMAKE_PRL_VERSION"))
134 target += libinfo.first("QMAKE_PRL_VERSION").replace(".", "");
135
136 const QStringList &in = libinfo.values("QMAKE_PRL_LIBS");
137 QStringList &out = project->values("QMAKE_PRL_LIBS");
138 for (QStringList::ConstIterator it = in.begin(); it != in.end(); ++it) {
139 if (!out.contains(*it))
140 out.append((*it));
141 }
142 return target;
143 }
144 }
145
146 if (!versionOverride.isEmpty())
147 return stem + versionOverride;
148
149 int biggest = -1;
150 if(!project->isActiveConfig("no_versionlink")) {
151 QDir dir(bd);
152 QStringList entries = dir.entryList();
153 QRegExp regx(QString("((lib)?%1([0-9]*))(%2)$").arg(dllStem).arg(ext), Qt::CaseInsensitive);
154 for(QStringList::Iterator it = entries.begin(); it != entries.end(); ++it) {
155 if(regx.exactMatch((*it))) {
156 if (!regx.cap(3).isEmpty()) {
157 bool ok = true;
158 int num = regx.cap(3).toInt(&ok);
159 biggest = qMax(biggest, (!ok ? -1 : num));
160 }
161 }
162 }
163 }
164 if (biggest != -1)
165 return stem + QString::number(biggest);
166
167 return QString();
168}
169
170bool GNUMakefileGenerator::findLibraries()
171{
172 QStringList &l = project->values("QMAKE_LIBS");
173
174 QList<QMakeLocalFileName> dirs;
175 {
176 QStringList &libpaths = project->values("QMAKE_LIBDIR");
177 for(QStringList::Iterator libpathit = libpaths.begin();
178 libpathit != libpaths.end(); ++libpathit)
179 dirs.append(QMakeLocalFileName((*libpathit)));
180 }
181
182 QStringList::Iterator it = l.begin();
183
184 do {
185 project->values("QMAKE_PRL_LIBS").clear();
186 bool erase = false;
187 for (; it != l.end(); erase ? (erase = false, it = l.erase(it)) : ++it) {
188 if((*it).startsWith("-L")) {
189 dirs.append(QMakeLocalFileName((*it).mid(2)));
190 } else {
191 QString stem = *it, out;
192
193 if (stem.startsWith("-l"))
194 stem = stem.mid(2);
195
196 QString suffix;
197 if (!project->isEmpty("QMAKE_" + stem.toUpper() + "_SUFFIX"))
198 suffix = project->first("QMAKE_" + stem.toUpper() + "_SUFFIX");
199 for (QList<QMakeLocalFileName>::Iterator dir_it = dirs.begin(); dir_it != dirs.end(); ++dir_it) {
200 QString best = findBestVersion((*dir_it).local(), stem,
201 QString("%1.lib").arg(suffix));
202 if (!best.isNull()) {
203 if (best.isEmpty()) {
204 // we are asked to discard this lib, do it
205 erase = true;
206 break;
207 }
208 out = best.prepend("-l");
209 break;
210 }
211 }
212 if (!out.isEmpty()) // We assume if it never finds it then its correct
213 if (!project->values("QMAKE_LIBS").contains(out))
214 (*it) = out;
215 }
216 }
217
218 // add the libraries from PRL and process them normally
219 QStringList l2 = project->values("QMAKE_PRL_LIBS");
220 int oldSize = l.size();
221 for (QStringList::ConstIterator it2 = l2.begin(); it2 != l2.end(); ++it2) {
222 if (!l.contains(*it2))
223 l.append(*it2);
224 }
225 it = l.begin() + oldSize;
226
227 } while(it != l.end());
228
229 return true;
230}
231
232bool GNUMakefileGenerator::writeMakefile(QTextStream &t)
233{
234 writeHeader(t);
235
236 /* function to convert from DOS-like to Unix-like space escaping in file
237 * names */
238 t << "null :=" << endl << "space := $(null) # end of the line" << endl;
239 t << "# function to change DOS-like space escaping to Unix-like" << endl;
240 t << "q = $(subst %,\\%,$(subst ;,\\;,$(subst &,\\&,"
241 "$(subst +,\\+,$(subst $(space),\\ ,$(subst \",,$(1)))))))" << endl << endl;
242
243 if(!project->values("QMAKE_FAILED_REQUIREMENTS").isEmpty()) {
244 t << "all clean:" << "\n\t"
245 << "@echo \"Some of the required modules ("
246 << var("QMAKE_FAILED_REQUIREMENTS") << ") are not available.\"" << "\n\t"
247 << "@echo \"Skipped.\"" << endl << endl;
248 writeMakeQmake(t);
249 return true;
250 }
251
252 if(project->first("TEMPLATE") == "app" ||
253 project->first("TEMPLATE") == "lib") {
254 if(Option::mkfile::do_stub_makefile) {
255 t << "QMAKE = " << (project->isEmpty("QMAKE_QMAKE") ? QString("qmake") : var("QMAKE_QMAKE")) << endl;
256 QStringList &qut = project->values("QMAKE_EXTRA_TARGETS");
257 for(QStringList::ConstIterator it = qut.begin(); it != qut.end(); ++it)
258 t << *it << " ";
259 t << "first all clean install distclean uninstall: qmake" << endl
260 << "qmake_all:" << endl;
261 writeMakeQmake(t);
262 if(project->isEmpty("QMAKE_NOFORCE"))
263 t << "FORCE:" << endl << endl;
264 return true;
265 }
266 writeGNUParts(t);
267 return MakefileGenerator::writeMakefile(t);
268 }
269 else if(project->first("TEMPLATE") == "subdirs") {
270 writeSubDirs(t);
271 return true;
272 }
273 return false;
274 }
275
276void GNUMakefileGenerator::writeGNUParts(QTextStream &t)
277{
278 t << "QMAKESPECDIR = " << quote << specdir() << quote << endl << endl;
279
280 writeStandardParts(t);
281
282 if (!preCompHeaderOut.isEmpty()) {
283 QString header = project->first("PRECOMPILED_HEADER");
284 QString cHeader = preCompHeaderOut + Option::dir_sep + "c";
285 t << escapeDependencyPath(cHeader) << ": " << escapeDependencyPath(header) << " "
286 << escapeDependencyPaths(findDependencies(header)).join(" \\\n\t\t")
287 << "\n\t" << mkdir_p_asstring(preCompHeaderOut)
288 << "\n\t" << "$(CC) -x c-header -c $(CFLAGS) $(INCPATH) -o " << cHeader << " " << header
289 << endl << endl;
290 QString cppHeader = preCompHeaderOut + Option::dir_sep + "c++";
291 t << escapeDependencyPath(cppHeader) << ": " << escapeDependencyPath(header) << " "
292 << escapeDependencyPaths(findDependencies(header)).join(" \\\n\t\t")
293 << "\n\t" << mkdir_p_asstring(preCompHeaderOut)
294 << "\n\t" << "$(CXX) -x c++-header -c $(CXXFLAGS) $(INCPATH) -o " << cppHeader << " " << header
295 << endl << endl;
296 }
297}
298
299void GNUMakefileGenerator::init()
300{
301 if(init_flag)
302 return;
303 init_flag = true;
304
305 if(project->first("TEMPLATE") == "app") {
306 mode = App;
307 project->values("QMAKE_APP_FLAG").append("1");
308 } else if(project->first("TEMPLATE") == "lib") {
309 mode = project->isActiveConfig("staticlib") ? StaticLib : DLL;
310 project->values("QMAKE_LIB_FLAG").append("1");
311 } else if(project->first("TEMPLATE") == "subdirs") {
312 MakefileGenerator::init();
313 if(project->isEmpty("QMAKE_COPY_FILE"))
314 project->values("QMAKE_COPY_FILE").append("$(COPY)");
315 if(project->isEmpty("QMAKE_COPY_DIR"))
316 project->values("QMAKE_COPY_DIR").append("$(COPY)");
317 if(project->isEmpty("QMAKE_INSTALL_FILE"))
318 project->values("QMAKE_INSTALL_FILE").append("$(COPY_FILE)");
319 if(project->isEmpty("QMAKE_INSTALL_PROGRAM"))
320 project->values("QMAKE_INSTALL_PROGRAM").append("$(COPY_FILE)");
321 if(project->isEmpty("QMAKE_INSTALL_DIR"))
322 project->values("QMAKE_INSTALL_DIR").append("$(COPY_DIR)");
323 if(project->values("MAKEFILE").isEmpty())
324 project->values("MAKEFILE").append("Makefile");
325 if(project->values("QMAKE_QMAKE").isEmpty())
326 project->values("QMAKE_QMAKE").append("qmake");
327 return;
328 }
329
330 project->values("TARGET_PRL").append(project->first("TARGET"));
331
332 processVars();
333
334 // LIBS defined in Profile comes first for gcc
335 project->values("QMAKE_LIBS") += escapeFilePaths(project->values("LIBS"));
336
337 QStringList &configs = project->values("CONFIG");
338
339 if(project->isActiveConfig("qt_dll"))
340 if(configs.indexOf("qt") == -1)
341 configs.append("qt");
342
343 if(project->isActiveConfig("dll")) {
344 QString destDir = "";
345 if(!project->first("DESTDIR").isEmpty())
346 destDir = Option::fixPathToTargetOS(project->first("DESTDIR") + Option::dir_sep, false, false);
347 }
348
349 MakefileGenerator::init();
350
351 // precomp
352 if (!project->first("PRECOMPILED_HEADER").isEmpty()
353 && project->isActiveConfig("precompile_header")) {
354 QString preCompHeader = var("PRECOMPILED_DIR")
355 + QFileInfo(project->first("PRECOMPILED_HEADER")).fileName();
356 preCompHeaderOut = preCompHeader + ".gch";
357 project->values("QMAKE_CLEAN").append(preCompHeaderOut + Option::dir_sep + "c");
358 project->values("QMAKE_CLEAN").append(preCompHeaderOut + Option::dir_sep + "c++");
359
360 project->values("QMAKE_RUN_CC").clear();
361 project->values("QMAKE_RUN_CC").append("$(CC) -c -include " + preCompHeader +
362 " $(CFLAGS) $(INCPATH) -o $obj $src");
363 project->values("QMAKE_RUN_CC_IMP").clear();
364 project->values("QMAKE_RUN_CC_IMP").append("$(CC) -c -include " + preCompHeader +
365 " $(CFLAGS) $(INCPATH) -o $@ $<");
366 project->values("QMAKE_RUN_CXX").clear();
367 project->values("QMAKE_RUN_CXX").append("$(CXX) -c -include " + preCompHeader +
368 " $(CXXFLAGS) $(INCPATH) -o $obj $src");
369 project->values("QMAKE_RUN_CXX_IMP").clear();
370 project->values("QMAKE_RUN_CXX_IMP").append("$(CXX) -c -include " + preCompHeader +
371 " $(CXXFLAGS) $(INCPATH) -o $@ $<");
372 }
373}
374
375void GNUMakefileGenerator::fixTargetExt()
376{
377 if (mode == App)
378 project->values("TARGET_EXT").append(".exe");
379 else if (mode == DLL)
380 project->values("TARGET_EXT").append(project->first("TARGET_VERSION_EXT") + ".dll");
381 else
382 project->values("TARGET_EXT").append(".lib");
383}
384
385void GNUMakefileGenerator::writeIncPart(QTextStream &t)
386{
387 t << "INCPATH =";
388
389 QString opt = var("QMAKE_CFLAGS_INCDIR");
390 QStringList &incs = project->values("INCLUDEPATH");
391 QString incsSemicolon;
392 for(QStringList::Iterator incit = incs.begin(); incit != incs.end(); ++incit) {
393 QString inc = escapeFilePath(*incit);
394 t << " " << opt << inc;
395 incsSemicolon += inc + Option::dirlist_sep;
396 }
397 t << " " << opt << "$(QMAKESPECDIR)" << endl;
398 incsSemicolon += "$(QMAKESPECDIR)";
399 t << "INCLUDEPATH = " << incsSemicolon << endl;
400 /* createCompilerResponseFiles() will need QAKESPECDIR expanded) */
401 project->values("INCLUDEPATH").append(specdir());
402}
403
404void GNUMakefileGenerator::writeLibsPart(QTextStream &t)
405{
406 if (mode == StaticLib) {
407 t << "LIB = " << var("QMAKE_LIB") << endl;
408 } else {
409 t << "LINK = " << var("QMAKE_LINK") << endl;
410 t << "LFLAGS = " << var("QMAKE_LFLAGS") << endl;
411 t << "LIBS =";
412 if(!project->values("QMAKE_LIBDIR").isEmpty())
413 writeLibDirPart(t);
414 QString opt = var("QMAKE_LFLAGS_LIB");
415 QString optL = var("QMAKE_LFLAGS_LIBDIR");
416 QStringList libs = project->values("QMAKE_LIBS");
417 for(QStringList::Iterator it = libs.begin(); it != libs.end(); ++it) {
418 QString lib = escapeFilePath(*it);
419 /* lib may be prefixed with -l which is commonly used in e.g. PRF
420 * (feature) files on all platforms; remove it before prepending
421 * the compiler-specific option. There is even more weird case
422 * when LIBS contains library paths prefixed with -L; we detect
423 * this as well and replace it with the proper option. */
424 if (lib.startsWith("-L")) {
425 lib = lib.mid(2);
426 t << " " << optL << lib;
427 } else {
428 if (lib.startsWith("-l"))
429 lib = lib.mid(2);
430 t << " " << opt << lib;
431 }
432 }
433 t << endl;
434 }
435}
436
437void GNUMakefileGenerator::writeLibDirPart(QTextStream &t)
438{
439 QString opt = var("QMAKE_LFLAGS_LIBDIR");
440 QStringList libDirs = project->values("QMAKE_LIBDIR");
441 for(QStringList::Iterator it = libDirs.begin(); it != libDirs.end(); ++it) {
442 QString libDir = escapeFilePath(*it);
443 /* libDir may be prefixed with -L which is commonly used in e.g. PRF
444 * (feature) files on all platforms; remove it before prepending
445 * the compiler-specific option */
446 if (libDir.startsWith("-L"))
447 libDir = libDir.mid(2);
448 t << " " << opt << libDir;
449 }
450}
451
452void GNUMakefileGenerator::writeObjectsPart(QTextStream &t)
453{
454 Win32MakefileGenerator::writeObjectsPart(t);
455 createLinkerResponseFiles(t);
456
457 /* this function is a nice place to also handle compiler options response
458 * files */
459 createCompilerResponseFiles(t);
460}
461
462void GNUMakefileGenerator::writeBuildRulesPart(QTextStream &t)
463{
464 t << "first: all" << endl;
465 t << "all: " << escapeDependencyPath(fileFixify(Option::output.fileName())) << " " << valGlue(escapeDependencyPaths(project->values("ALL_DEPS"))," "," "," ") << escapeFileVars(" $(DESTDIR_TARGET)") << endl << endl;
466 t << escapeFileVars("$(DESTDIR_TARGET): ") << var("PRE_TARGETDEPS") << " $(OBJECTS) " << var("POST_TARGETDEPS");
467 if (!project->isEmpty("QMAKE_PRE_LINK"))
468 t << "\n\t" <<var("QMAKE_PRE_LINK");
469 if (mode == StaticLib) {
470 /* static library */
471 t << "\n\t" << var("QMAKE_RUN_LIB");
472 } else {
473 /* application or DLL */
474 t << "\n\t" << var("QMAKE_RUN_LINK");
475 if (!project->isEmpty("RES_FILE") && !project->isEmpty("QMAKE_RUN_RC2EXE")) {
476 t << "\n\t" << var("QMAKE_RUN_RC2EXE");
477 }
478 }
479 if(!project->isEmpty("QMAKE_POST_LINK"))
480 t << "\n\t" <<var("QMAKE_POST_LINK");
481 t << endl;
482}
483
484void GNUMakefileGenerator::writeRcAndDefVariables(QTextStream &t)
485{
486 if (!project->isEmpty("RC_FILE")) {
487 t << "RC_FILE = " << escapeFilePath(var("RC_FILE")) << endl;
488 }
489 if (!project->isEmpty("RES_FILE")) {
490 t << "RES_FILE = " << valList(escapeFilePaths(project->values("RES_FILE"))) << endl;
491 }
492
493 if (project->isEmpty("DEF_FILE")) {
494 /* no DEF file supplied, we will generate one */
495 if (mode == DLL) {
496 t << "DEF_FILE = $(basename $(DESTDIR_TARGET)).def" << endl;
497 project->values("QMAKE_CLEAN").append("$(DEF_FILE)");
498 project->values("POST_TARGETDEPS") += escapeFileVars("$(DEF_FILE)");
499 if (!project->isEmpty("DEF_FILE_TEMPLATE")) {
500 t << "DEF_FILE_TEMPLATE = " << escapeFilePath(var("DEF_FILE_TEMPLATE")) << endl;
501 project->values("QMAKE_GENDEF_DEPS") += escapeFileVars("$(DEF_FILE_TEMPLATE)");
502 }
503 if (!project->isEmpty("DEF_FILE_MAP")) {
504 t << "DEF_FILE_MAP = " << escapeFilePath(var("DEF_FILE_MAP")) << endl;
505 project->values("QMAKE_GENDEF_DEPS") += escapeFileVars("$(DEF_FILE_MAP)");
506 }
507 }
508 } else {
509 if (!project->isEmpty("DEF_FILE_TEMPLATE")) {
510 fprintf(stderr, "Both DEF_FILE and DEF_FILE_TEMPLATE are specified.\n");
511 fprintf(stderr, "Please specify one of them, not both.");
512 exit(1);
513 }
514 t << "DEF_FILE = " << escapeFilePath(var("DEF_FILE")) << endl;
515 project->values("POST_TARGETDEPS") += escapeFileVars("$(DEF_FILE)");
516 }
517
518 if (mode == DLL && !project->isEmpty("QMAKE_RUN_IMPLIB")) {
519 t << "TARGET_IMPLIB = $(basename $(DESTDIR_TARGET)).lib" << endl;
520 project->values("QMAKE_CLEAN").append("$(TARGET_IMPLIB)");
521 project->values("POST_TARGETDEPS") += escapeFileVars("$(TARGET_IMPLIB)");
522 }
523}
524
525void GNUMakefileGenerator::writeRcAndDefPart(QTextStream &t)
526{
527 if (!project->isEmpty("RC_FILE") && !project->isEmpty("RES_FILE") &&
528 !project->isEmpty("QMAKE_RUN_RC2RES")) {
529 t << escapeFileVars("$(RES_FILE): $(RC_FILE)\n\t");
530 t << var("QMAKE_RUN_RC2RES") << endl;
531 }
532
533 if (mode == DLL) {
534 if (project->isEmpty("DEF_FILE")) {
535 /* generate a DEF file for the DLL when not supplied */
536 t << escapeFileVars("$(DEF_FILE): ") << var("QMAKE_GENDEF_DEPS");
537 t << valGlue(var("QMAKE_RUN_GENDEF").split(";;"), "\n\t", "\n\t", "") << endl;
538 }
539 if (!project->isEmpty("QMAKE_RUN_IMPLIB")) {
540 /* generate the import library */
541 t << escapeFileVars("$(TARGET_IMPLIB): ") << escapeFileVars("$(DEF_FILE)");
542 t << "\n\t" << var("QMAKE_RUN_IMPLIB") << endl;
543 }
544 }
545}
546
547void GNUMakefileGenerator::processRcFileVar()
548{
549 if (Option::qmake_mode == Option::QMAKE_GENERATE_NOTHING)
550 return;
551
552 if (!project->isEmpty("RC_FILE")) {
553 if (!project->isEmpty("RES_FILE")) {
554 fprintf(stderr, "Both rc and res file specified.\n");
555 fprintf(stderr, "Please specify one of them, not both.");
556 exit(1);
557 }
558 project->values("RES_FILE").prepend(escapeFilePath(QString("$(OBJECTS_DIR)") +
559 QDir::separator() +
560 QFileInfo(var("RC_FILE")).baseName() +
561 ".res"));
562 project->values("CLEAN_FILES") += "$(RES_FILE)";
563 }
564
565 if (!project->isEmpty("RES_FILE"))
566 project->values("POST_TARGETDEPS") += escapeFileVars("$(RES_FILE)");
567}
568
569void GNUMakefileGenerator::processPrlVariable(const QString &var, const QStringList &l)
570{
571 // we don't do any processing here; everything we need is done in
572 // GNUMakefileGenerator::findLibraries()
573 return;
574}
575
576void GNUMakefileGenerator::processPrlFiles()
577{
578 // we don't do any processing here; everything we need is done in
579 // GNUMakefileGenerator::findLibraries()
580 return;
581}
582
583QStringList &GNUMakefileGenerator::findDependencies(const QString &file)
584{
585 QStringList &aList = MakefileGenerator::findDependencies(file);
586 // Note: The QMAKE_IMAGE_COLLECTION file have all images
587 // as dependency, so don't add precompiled header then
588 if (file == project->first("QMAKE_IMAGE_COLLECTION")
589 || preCompHeaderOut.isEmpty())
590 return aList;
591 for (QStringList::Iterator it = Option::c_ext.begin(); it != Option::c_ext.end(); ++it) {
592 if (file.endsWith(*it)) {
593 QString cHeader = preCompHeaderOut + Option::dir_sep + "c";
594 if (!aList.contains(cHeader))
595 aList += cHeader;
596 break;
597 }
598 }
599 for (QStringList::Iterator it = Option::cpp_ext.begin(); it != Option::cpp_ext.end(); ++it) {
600 if (file.endsWith(*it)) {
601 QString cppHeader = preCompHeaderOut + Option::dir_sep + "c++";
602 if (!aList.contains(cppHeader))
603 aList += cppHeader;
604 break;
605 }
606 }
607 return aList;
608}
609
610void GNUMakefileGenerator::writeProjectVarToStream(QTextStream &t, const QString &var)
611{
612 QStringList &list = project->values(var);
613 for(QStringList::Iterator it = list.begin(); it != list.end(); ++it) {
614 t << (*it) << endl;
615 }
616}
617
618QString GNUMakefileGenerator::makeResponseFileName(const QString &base)
619{
620 QString fileName = base + "." + var("TARGET");
621 if (!var("BUILD_NAME").isEmpty()) {
622 fileName += "." + var("BUILD_NAME");
623 }
624 fileName += ".rsp";
625 QString filePath = project->first("OBJECTS_DIR");
626 if (filePath.isEmpty())
627 filePath = Option::output_dir;
628 filePath = Option::fixPathToTargetOS(filePath + QDir::separator() + fileName);
629 return filePath;
630}
631
632void GNUMakefileGenerator::createCompilerResponseFiles(QTextStream &t)
633{
634 static const char *vars[] = { "CFLAGS", "CXXFLAGS", "DEFINES", "INCPATH" };
635
636 /* QMAKE_XXX_RSP_VAR is used as a flag whether it is necessary to
637 * generate response files to overcome the 1024 chars CMD.EXE limitation.
638 * When this variable is defined, a response file with the relevant
639 * information will be generated and its full path will be stored in an
640 * environment variable with the given name which can then be referred to in
641 * other places of qmake.conf (e.g. rules) */
642
643 for (size_t i = 0; i < sizeof(vars)/sizeof(vars[0]); ++i) {
644 QString rspVar =
645 project->first(QString().sprintf("QMAKE_%s_RSP_VAR", vars[i]));
646 if (!rspVar.isEmpty()) {
647 QString fileName = makeResponseFileName(vars[i]);
648 t << rspVar.leftJustified(14) << "= " << fileName << endl;
649 QFile file(fileName);
650 if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
651 QTextStream rt(&file);
652 if (!qstrcmp(vars[i], "CFLAGS")) {
653 rt << varGlue("QMAKE_CFLAGS", QString::null, "\n", "\n");
654 } else if (!qstrcmp(vars[i], "CXXFLAGS")) {
655 rt << varGlue("QMAKE_CXXFLAGS", QString::null, "\n", "\n");
656 } else if (!qstrcmp(vars[i], "DEFINES")) {
657 rt << varGlue("PRL_EXPORT_DEFINES", "-D", "\n-D", "\n")
658 << varGlue("DEFINES", "-D", "\n-D", "\n");
659 } else if (!qstrcmp(vars[i], "INCPATH")) {
660 QString opt = var("QMAKE_CFLAGS_INCDIR");
661 rt << varGlue("INCLUDEPATH", opt, "\n" + opt, "\n");
662 } else {
663 Q_ASSERT(false);
664 }
665 rt.flush();
666 file.close();
667 }
668 project->values("QMAKE_DISTCLEAN").append("$(" + rspVar + ")");
669 }
670 }
671}
672
673void GNUMakefileGenerator::createLinkerResponseFiles(QTextStream &t)
674{
675 /* see createCompilerResponseFiles() */
676 QString var = project->first("QMAKE_OBJECTS_RSP_VAR");
677 if (!var.isEmpty()) {
678 QString fileName = makeResponseFileName("OBJECTS");
679 t << var.leftJustified(14) << "= " << fileName << endl;
680 QFile file(fileName);
681 if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
682 QTextStream rt(&file);
683 rt << varGlue("OBJECTS", QString::null, "\n", "\n");
684 rt.flush();
685 file.close();
686 }
687 project->values("QMAKE_DISTCLEAN").append("$(" + var + ")");
688 }
689}
690
691QString GNUMakefileGenerator::escapeFileVars(const QString &vars)
692{
693 /* In DOS environment, we escape spaces and other illegal characters in
694 * filenames with double quotes. However, this is not appropriate for make
695 * rule definitions (targets/dependencies) where Unix escaping is
696 * expected. If we'd deal only with immediate strings, we could provide
697 * necessary escaping in place, but we often use make variables instead of
698 * direct file names so we must perform such escaping on the fly. This is
699 * what we do here using the q function that we define in writeMakefile().*/
700 if (isDosLikeShell()) {
701 QString ret = vars;
702 QRegExp rx = QRegExp("\\$\\((.+)\\)");
703 rx.setMinimal(true);
704 ret.replace(rx, "$(call q,$(\\1))");
705 return ret;
706 }
707 return vars;
708}
709
710QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.