source: trunk/qmake/generators/win32/mingw_make.cpp@ 561

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

trunk: Merged in qt 4.6.1 sources.

File size: 18.1 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 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** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "mingw_make.h"
43#include "option.h"
44#include "meta.h"
45#include <qregexp.h>
46#include <qdir.h>
47#include <stdlib.h>
48#include <time.h>
49
50QT_BEGIN_NAMESPACE
51
52MingwMakefileGenerator::MingwMakefileGenerator() : Win32MakefileGenerator(), init_flag(false)
53{
54 if (Option::shellPath.isEmpty())
55 quote = "\"";
56 else
57 quote = "'";
58}
59
60bool MingwMakefileGenerator::isDosLikeShell() const
61{
62#ifdef Q_OS_WIN
63 return Option::shellPath.isEmpty();
64#else
65 return Win32MakefileGenerator::isDosLikeShell();
66#endif
67}
68
69QString MingwMakefileGenerator::escapeDependencyPath(const QString &path) const
70{
71 QString ret = path;
72 ret.remove('\"');
73 ret.replace('\\', "/");
74 ret.replace(' ', "\\ ");
75 return ret;
76}
77
78QString MingwMakefileGenerator::getLibTarget()
79{
80 return QString("lib" + project->first("TARGET") + project->first("TARGET_VERSION_EXT") + ".a");
81}
82
83bool MingwMakefileGenerator::findLibraries()
84{
85 return findLibraries("QMAKE_LIBS") && findLibraries("QMAKE_LIBS_PRIVATE");
86}
87
88bool MingwMakefileGenerator::findLibraries(const QString &where)
89{
90 QStringList &l = project->values(where);
91
92 QList<QMakeLocalFileName> dirs;
93 {
94 QStringList &libpaths = project->values("QMAKE_LIBDIR");
95 for(QStringList::Iterator libpathit = libpaths.begin();
96 libpathit != libpaths.end(); ++libpathit)
97 dirs.append(QMakeLocalFileName((*libpathit)));
98 }
99
100 QStringList::Iterator it = l.begin();
101 while (it != l.end()) {
102 if ((*it).startsWith("-l")) {
103 QString steam = (*it).mid(2), out;
104 QString suffix;
105 if (!project->isEmpty("QMAKE_" + steam.toUpper() + "_SUFFIX"))
106 suffix = project->first("QMAKE_" + steam.toUpper() + "_SUFFIX");
107 for (QList<QMakeLocalFileName>::Iterator dir_it = dirs.begin(); dir_it != dirs.end(); ++dir_it) {
108 QString extension;
109 int ver = findHighestVersion((*dir_it).local(), steam, "dll.a|a");
110 if (ver != -1)
111 extension += QString::number(ver);
112 extension += suffix;
113 if(QMakeMetaInfo::libExists((*dir_it).local() + Option::dir_sep + steam) ||
114 exists((*dir_it).local() + Option::dir_sep + steam + extension + ".a") ||
115 exists((*dir_it).local() + Option::dir_sep + steam + extension + ".dll.a")) {
116 out = (*it) + extension;
117 break;
118 }
119 }
120 if (!out.isEmpty()) // We assume if it never finds it that its correct
121 (*it) = out;
122 } else if((*it).startsWith("-L")) {
123 dirs.append(QMakeLocalFileName((*it).mid(2)));
124 }
125
126 ++it;
127 }
128 return true;
129}
130
131bool MingwMakefileGenerator::writeMakefile(QTextStream &t)
132{
133 writeHeader(t);
134 if(!project->values("QMAKE_FAILED_REQUIREMENTS").isEmpty()) {
135 t << "all clean:" << "\n\t"
136 << "@echo \"Some of the required modules ("
137 << var("QMAKE_FAILED_REQUIREMENTS") << ") are not available.\"" << "\n\t"
138 << "@echo \"Skipped.\"" << endl << endl;
139 writeMakeQmake(t);
140 return true;
141 }
142
143 if(project->first("TEMPLATE") == "app" ||
144 project->first("TEMPLATE") == "lib") {
145 if(Option::mkfile::do_stub_makefile) {
146 t << "QMAKE = " << (project->isEmpty("QMAKE_QMAKE") ? QString("qmake") : var("QMAKE_QMAKE")) << endl;
147 QStringList &qut = project->values("QMAKE_EXTRA_TARGETS");
148 for(QStringList::ConstIterator it = qut.begin(); it != qut.end(); ++it)
149 t << *it << " ";
150 t << "first all clean install distclean uninstall: qmake" << endl
151 << "qmake_all:" << endl;
152 writeMakeQmake(t);
153 if(project->isEmpty("QMAKE_NOFORCE"))
154 t << "FORCE:" << endl << endl;
155 return true;
156 }
157 writeMingwParts(t);
158 return MakefileGenerator::writeMakefile(t);
159 }
160 else if(project->first("TEMPLATE") == "subdirs") {
161 writeSubDirs(t);
162 return true;
163 }
164 return false;
165 }
166
167void createLdObjectScriptFile(const QString &fileName, const QStringList &objList)
168{
169 QString filePath = Option::output_dir + QDir::separator() + fileName;
170 QFile file(filePath);
171 if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
172 QTextStream t(&file);
173 t << "INPUT(" << endl;
174 for (QStringList::ConstIterator it = objList.constBegin(); it != objList.constEnd(); ++it) {
175 if (QDir::isRelativePath(*it))
176 t << "./" << *it << endl;
177 else
178 t << *it << endl;
179 }
180 t << ");" << endl;
181 t.flush();
182 file.close();
183 }
184}
185
186void createArObjectScriptFile(const QString &fileName, const QString &target, const QStringList &objList)
187{
188 QString filePath = Option::output_dir + QDir::separator() + fileName;
189 QFile file(filePath);
190 if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
191 QTextStream t(&file);
192 t << "CREATE " << target << endl;
193 for (QStringList::ConstIterator it = objList.constBegin(); it != objList.constEnd(); ++it) {
194 if (QDir::isRelativePath(*it))
195 t << "ADDMOD " << *it << endl;
196 else
197 t << *it << endl;
198 }
199 t << "SAVE" << endl;
200 t.flush();
201 file.close();
202 }
203}
204
205void MingwMakefileGenerator::writeMingwParts(QTextStream &t)
206{
207 writeStandardParts(t);
208
209 if (!preCompHeaderOut.isEmpty()) {
210 QString header = project->first("PRECOMPILED_HEADER");
211 QString cHeader = preCompHeaderOut + Option::dir_sep + "c";
212 t << escapeDependencyPath(cHeader) << ": " << escapeDependencyPath(header) << " "
213 << escapeDependencyPaths(findDependencies(header)).join(" \\\n\t\t")
214 << "\n\t" << mkdir_p_asstring(preCompHeaderOut)
215 << "\n\t" << "$(CC) -x c-header -c $(CFLAGS) $(INCPATH) -o " << cHeader << " " << header
216 << endl << endl;
217 QString cppHeader = preCompHeaderOut + Option::dir_sep + "c++";
218 t << escapeDependencyPath(cppHeader) << ": " << escapeDependencyPath(header) << " "
219 << escapeDependencyPaths(findDependencies(header)).join(" \\\n\t\t")
220 << "\n\t" << mkdir_p_asstring(preCompHeaderOut)
221 << "\n\t" << "$(CXX) -x c++-header -c $(CXXFLAGS) $(INCPATH) -o " << cppHeader << " " << header
222 << endl << endl;
223 }
224}
225
226void MingwMakefileGenerator::init()
227{
228 if(init_flag)
229 return;
230 init_flag = true;
231
232 /* this should probably not be here, but I'm using it to wrap the .t files */
233 if(project->first("TEMPLATE") == "app")
234 project->values("QMAKE_APP_FLAG").append("1");
235 else if(project->first("TEMPLATE") == "lib")
236 project->values("QMAKE_LIB_FLAG").append("1");
237 else if(project->first("TEMPLATE") == "subdirs") {
238 MakefileGenerator::init();
239 if(project->isEmpty("QMAKE_COPY_FILE"))
240 project->values("QMAKE_COPY_FILE").append("$(COPY)");
241 if(project->isEmpty("QMAKE_COPY_DIR"))
242 project->values("QMAKE_COPY_DIR").append("xcopy /s /q /y /i");
243 if(project->isEmpty("QMAKE_INSTALL_FILE"))
244 project->values("QMAKE_INSTALL_FILE").append("$(COPY_FILE)");
245 if(project->isEmpty("QMAKE_INSTALL_PROGRAM"))
246 project->values("QMAKE_INSTALL_PROGRAM").append("$(COPY_FILE)");
247 if(project->isEmpty("QMAKE_INSTALL_DIR"))
248 project->values("QMAKE_INSTALL_DIR").append("$(COPY_DIR)");
249 if(project->values("MAKEFILE").isEmpty())
250 project->values("MAKEFILE").append("Makefile");
251 if(project->values("QMAKE_QMAKE").isEmpty())
252 project->values("QMAKE_QMAKE").append("qmake");
253 return;
254 }
255
256 project->values("TARGET_PRL").append(project->first("TARGET"));
257
258 processVars();
259
260 if (!project->values("RES_FILE").isEmpty()) {
261 project->values("QMAKE_LIBS") += escapeFilePaths(project->values("RES_FILE"));
262 }
263
264 // LIBS defined in Profile comes first for gcc
265 project->values("QMAKE_LIBS") += escapeFilePaths(project->values("LIBS"));
266 project->values("QMAKE_LIBS_PRIVATE") += escapeFilePaths(project->values("LIBS_PRIVATE"));
267
268 QString targetfilename = project->values("TARGET").first();
269 QStringList &configs = project->values("CONFIG");
270
271 if(project->isActiveConfig("qt_dll"))
272 if(configs.indexOf("qt") == -1)
273 configs.append("qt");
274
275 if(project->isActiveConfig("dll")) {
276 QString destDir = "";
277 if(!project->first("DESTDIR").isEmpty())
278 destDir = Option::fixPathToTargetOS(project->first("DESTDIR") + Option::dir_sep, false, false);
279 project->values("MINGW_IMPORT_LIB").prepend(destDir + "lib" + project->first("TARGET")
280 + project->first("TARGET_VERSION_EXT") + ".a");
281 project->values("QMAKE_LFLAGS").append(QString("-Wl,--out-implib,") + project->first("MINGW_IMPORT_LIB"));
282 }
283
284 if(!project->values("DEF_FILE").isEmpty())
285 project->values("QMAKE_LFLAGS").append(QString("-Wl,") + project->first("DEF_FILE"));
286
287 MakefileGenerator::init();
288
289 // precomp
290 if (!project->first("PRECOMPILED_HEADER").isEmpty()
291 && project->isActiveConfig("precompile_header")) {
292 QString preCompHeader = var("PRECOMPILED_DIR")
293 + QFileInfo(project->first("PRECOMPILED_HEADER")).fileName();
294 preCompHeaderOut = preCompHeader + ".gch";
295 project->values("QMAKE_CLEAN").append(preCompHeaderOut + Option::dir_sep + "c");
296 project->values("QMAKE_CLEAN").append(preCompHeaderOut + Option::dir_sep + "c++");
297
298 project->values("QMAKE_RUN_CC").clear();
299 project->values("QMAKE_RUN_CC").append("$(CC) -c -include " + preCompHeader +
300 " $(CFLAGS) $(INCPATH) -o $obj $src");
301 project->values("QMAKE_RUN_CC_IMP").clear();
302 project->values("QMAKE_RUN_CC_IMP").append("$(CC) -c -include " + preCompHeader +
303 " $(CFLAGS) $(INCPATH) -o $@ $<");
304 project->values("QMAKE_RUN_CXX").clear();
305 project->values("QMAKE_RUN_CXX").append("$(CXX) -c -include " + preCompHeader +
306 " $(CXXFLAGS) $(INCPATH) -o $obj $src");
307 project->values("QMAKE_RUN_CXX_IMP").clear();
308 project->values("QMAKE_RUN_CXX_IMP").append("$(CXX) -c -include " + preCompHeader +
309 " $(CXXFLAGS) $(INCPATH) -o $@ $<");
310 }
311
312 if(project->isActiveConfig("dll")) {
313 project->values("QMAKE_CLEAN").append(project->first("MINGW_IMPORT_LIB"));
314 }
315}
316
317void MingwMakefileGenerator::fixTargetExt()
318{
319 if (project->isActiveConfig("staticlib") && project->first("TEMPLATE") == "lib") {
320 project->values("TARGET_EXT").append(".a");
321 project->values("QMAKE_LFLAGS").append("-static");
322 project->values("TARGET").first() = "lib" + project->first("TARGET");
323 } else {
324 Win32MakefileGenerator::fixTargetExt();
325 }
326}
327
328void MingwMakefileGenerator::writeIncPart(QTextStream &t)
329{
330 t << "INCPATH = ";
331
332 QStringList &incs = project->values("INCLUDEPATH");
333 for(QStringList::Iterator incit = incs.begin(); incit != incs.end(); ++incit) {
334 QString inc = (*incit);
335 inc.replace(QRegExp("\\\\$"), "");
336 inc.replace(QRegExp("\""), "");
337 t << "-I" << quote << inc << quote << " ";
338 }
339 t << "-I" << quote << specdir() << quote
340 << endl;
341}
342
343void MingwMakefileGenerator::writeLibsPart(QTextStream &t)
344{
345 if(project->isActiveConfig("staticlib") && project->first("TEMPLATE") == "lib") {
346 t << "LIB = " << var("QMAKE_LIB") << endl;
347 } else {
348 t << "LINK = " << var("QMAKE_LINK") << endl;
349 t << "LFLAGS = " << var("QMAKE_LFLAGS") << endl;
350 t << "LIBS = ";
351 if(!project->values("QMAKE_LIBDIR").isEmpty())
352 writeLibDirPart(t);
353 t << var("QMAKE_LIBS").replace(QRegExp("(\\slib|^lib)")," -l") << ' '
354 << var("QMAKE_LIBS_PRIVATE").replace(QRegExp("(\\slib|^lib)")," -l") << endl;
355 }
356}
357
358void MingwMakefileGenerator::writeLibDirPart(QTextStream &t)
359{
360 QStringList libDirs = project->values("QMAKE_LIBDIR");
361 for (int i = 0; i < libDirs.size(); ++i)
362 libDirs[i].remove("\"");
363 t << valGlue(libDirs,"-L"+quote,quote+" -L" +quote,quote) << " ";
364}
365
366void MingwMakefileGenerator::writeObjectsPart(QTextStream &t)
367{
368 if (project->values("OBJECTS").count() < var("QMAKE_LINK_OBJECT_MAX").toInt()) {
369 objectsLinkLine = "$(OBJECTS)";
370 } else if (project->isActiveConfig("staticlib") && project->first("TEMPLATE") == "lib") {
371 QString ar_script_file = var("QMAKE_LINK_OBJECT_SCRIPT") + "." + var("TARGET");
372 if (!var("BUILD_NAME").isEmpty()) {
373 ar_script_file += "." + var("BUILD_NAME");
374 }
375 createArObjectScriptFile(ar_script_file, var("DEST_TARGET"), project->values("OBJECTS"));
376 objectsLinkLine = "ar -M < " + ar_script_file;
377 } else {
378 QString ld_script_file = var("QMAKE_LINK_OBJECT_SCRIPT") + "." + var("TARGET");
379 if (!var("BUILD_NAME").isEmpty()) {
380 ld_script_file += "." + var("BUILD_NAME");
381 }
382 createLdObjectScriptFile(ld_script_file, project->values("OBJECTS"));
383 objectsLinkLine = ld_script_file;
384 }
385 Win32MakefileGenerator::writeObjectsPart(t);
386}
387
388void MingwMakefileGenerator::writeBuildRulesPart(QTextStream &t)
389{
390 t << "first: all" << endl;
391 t << "all: " << escapeDependencyPath(fileFixify(Option::output.fileName())) << " " << valGlue(escapeDependencyPaths(project->values("ALL_DEPS"))," "," "," ") << " $(DESTDIR_TARGET)" << endl << endl;
392 t << "$(DESTDIR_TARGET): " << var("PRE_TARGETDEPS") << " $(OBJECTS) " << var("POST_TARGETDEPS");
393 if(!project->isEmpty("QMAKE_PRE_LINK"))
394 t << "\n\t" <<var("QMAKE_PRE_LINK");
395 if(project->isActiveConfig("staticlib") && project->first("TEMPLATE") == "lib") {
396 if (project->values("OBJECTS").count() < var("QMAKE_LINK_OBJECT_MAX").toInt()) {
397 t << "\n\t" << "$(LIB) $(DESTDIR_TARGET) " << objectsLinkLine << " " ;
398 } else {
399 t << "\n\t" << objectsLinkLine << " " ;
400 }
401 } else {
402 t << "\n\t" << "$(LINK) $(LFLAGS) -o $(DESTDIR_TARGET) " << objectsLinkLine << " " << " $(LIBS)";
403 }
404 if(!project->isEmpty("QMAKE_POST_LINK"))
405 t << "\n\t" <<var("QMAKE_POST_LINK");
406 t << endl;
407}
408
409void MingwMakefileGenerator::writeRcFilePart(QTextStream &t)
410{
411 const QString rc_file = fileFixify(project->first("RC_FILE"));
412
413 QString incPathStr = fileInfo(rc_file).path();
414 if (incPathStr != "." && QDir::isRelativePath(incPathStr))
415 incPathStr.prepend("./");
416
417 if (!rc_file.isEmpty()) {
418 t << escapeDependencyPath(var("RES_FILE")) << ": " << rc_file << "\n\t"
419 << var("QMAKE_RC") << " -i " << rc_file << " -o " << var("RES_FILE")
420 << " --include-dir=" << incPathStr << endl << endl;
421 }
422}
423
424void MingwMakefileGenerator::processPrlVariable(const QString &var, const QStringList &l)
425{
426 if (var == "QMAKE_PRL_LIBS") {
427 QString where = "QMAKE_LIBS";
428 if (!project->isEmpty("QMAKE_INTERNAL_PRL_LIBS"))
429 where = project->first("QMAKE_INTERNAL_PRL_LIBS");
430 QStringList &out = project->values(where);
431 for (QStringList::ConstIterator it = l.begin(); it != l.end(); ++it) {
432 out.removeAll((*it));
433 out.append((*it));
434 }
435 } else {
436 Win32MakefileGenerator::processPrlVariable(var, l);
437 }
438}
439
440QStringList &MingwMakefileGenerator::findDependencies(const QString &file)
441{
442 QStringList &aList = MakefileGenerator::findDependencies(file);
443 // Note: The QMAKE_IMAGE_COLLECTION file have all images
444 // as dependency, so don't add precompiled header then
445 if (file == project->first("QMAKE_IMAGE_COLLECTION")
446 || preCompHeaderOut.isEmpty())
447 return aList;
448 for (QStringList::Iterator it = Option::c_ext.begin(); it != Option::c_ext.end(); ++it) {
449 if (file.endsWith(*it)) {
450 QString cHeader = preCompHeaderOut + Option::dir_sep + "c";
451 if (!aList.contains(cHeader))
452 aList += cHeader;
453 break;
454 }
455 }
456 for (QStringList::Iterator it = Option::cpp_ext.begin(); it != Option::cpp_ext.end(); ++it) {
457 if (file.endsWith(*it)) {
458 QString cppHeader = preCompHeaderOut + Option::dir_sep + "c++";
459 if (!aList.contains(cppHeader))
460 aList += cppHeader;
461 break;
462 }
463 }
464 return aList;
465}
466
467QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.