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

Last change on this file since 671 was 671, checked in by Dmitry A. Kuminov, 15 years ago

qmake: os2/gnumake: Fixed r670 regression.

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