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

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

qmake/GNUMAKE/os/2: Add the MAKEFILE variable to the generated make file that contains its name. Always convert separators to native when escaping paths for the DOS-like command processors.

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