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

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

global: Updated year to 2010 in OS/2-specific headers.

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