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

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

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 18.2 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 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 = " << 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 t << "ADDMOD " << *it << endl;
195 }
196 t << "SAVE" << endl;
197 t.flush();
198 file.close();
199 }
200}
201
202void MingwMakefileGenerator::writeMingwParts(QTextStream &t)
203{
204 writeStandardParts(t);
205
206 if (!preCompHeaderOut.isEmpty()) {
207 QString header = project->first("PRECOMPILED_HEADER");
208 QString cHeader = preCompHeaderOut + Option::dir_sep + "c";
209 t << escapeDependencyPath(cHeader) << ": " << escapeDependencyPath(header) << " "
210 << escapeDependencyPaths(findDependencies(header)).join(" \\\n\t\t")
211 << "\n\t" << mkdir_p_asstring(preCompHeaderOut)
212 << "\n\t" << "$(CC) -x c-header -c $(CFLAGS) $(INCPATH) -o " << cHeader << " " << header
213 << endl << endl;
214 QString cppHeader = preCompHeaderOut + Option::dir_sep + "c++";
215 t << escapeDependencyPath(cppHeader) << ": " << escapeDependencyPath(header) << " "
216 << escapeDependencyPaths(findDependencies(header)).join(" \\\n\t\t")
217 << "\n\t" << mkdir_p_asstring(preCompHeaderOut)
218 << "\n\t" << "$(CXX) -x c++-header -c $(CXXFLAGS) $(INCPATH) -o " << cppHeader << " " << header
219 << endl << endl;
220 }
221}
222
223void MingwMakefileGenerator::init()
224{
225 if(init_flag)
226 return;
227 init_flag = true;
228
229 /* this should probably not be here, but I'm using it to wrap the .t files */
230 if(project->first("TEMPLATE") == "app")
231 project->values("QMAKE_APP_FLAG").append("1");
232 else if(project->first("TEMPLATE") == "lib")
233 project->values("QMAKE_LIB_FLAG").append("1");
234 else if(project->first("TEMPLATE") == "subdirs") {
235 MakefileGenerator::init();
236 if(project->isEmpty("QMAKE_COPY_FILE"))
237 project->values("QMAKE_COPY_FILE").append("$(COPY)");
238 if(project->isEmpty("QMAKE_COPY_DIR"))
239 project->values("QMAKE_COPY_DIR").append("xcopy /s /q /y /i");
240 if(project->isEmpty("QMAKE_INSTALL_FILE"))
241 project->values("QMAKE_INSTALL_FILE").append("$(COPY_FILE)");
242 if(project->isEmpty("QMAKE_INSTALL_PROGRAM"))
243 project->values("QMAKE_INSTALL_PROGRAM").append("$(COPY_FILE)");
244 if(project->isEmpty("QMAKE_INSTALL_DIR"))
245 project->values("QMAKE_INSTALL_DIR").append("$(COPY_DIR)");
246 if(project->values("MAKEFILE").isEmpty())
247 project->values("MAKEFILE").append("Makefile");
248 return;
249 }
250
251 project->values("TARGET_PRL").append(project->first("TARGET"));
252
253 processVars();
254
255 if (!project->values("RES_FILE").isEmpty()) {
256 project->values("QMAKE_LIBS") += escapeFilePaths(project->values("RES_FILE"));
257 }
258
259 // LIBS defined in Profile comes first for gcc
260 project->values("QMAKE_LIBS") += escapeFilePaths(project->values("LIBS"));
261 project->values("QMAKE_LIBS_PRIVATE") += escapeFilePaths(project->values("LIBS_PRIVATE"));
262
263 QString targetfilename = project->values("TARGET").first();
264 QStringList &configs = project->values("CONFIG");
265
266 if(project->isActiveConfig("qt_dll"))
267 if(configs.indexOf("qt") == -1)
268 configs.append("qt");
269
270 if(project->isActiveConfig("dll")) {
271 QString destDir = "";
272 if(!project->first("DESTDIR").isEmpty())
273 destDir = Option::fixPathToTargetOS(project->first("DESTDIR") + Option::dir_sep, false, false);
274 project->values("MINGW_IMPORT_LIB").prepend(destDir + "lib" + project->first("TARGET")
275 + project->first("TARGET_VERSION_EXT") + ".a");
276 project->values("QMAKE_LFLAGS").append(QString("-Wl,--out-implib,") + project->first("MINGW_IMPORT_LIB"));
277 }
278
279 if(!project->values("DEF_FILE").isEmpty())
280 project->values("QMAKE_LFLAGS").append(QString("-Wl,") + project->first("DEF_FILE"));
281
282 MakefileGenerator::init();
283
284 // precomp
285 if (!project->first("PRECOMPILED_HEADER").isEmpty()
286 && project->isActiveConfig("precompile_header")) {
287 QString preCompHeader = var("PRECOMPILED_DIR")
288 + QFileInfo(project->first("PRECOMPILED_HEADER")).fileName();
289 preCompHeaderOut = preCompHeader + ".gch";
290 project->values("QMAKE_CLEAN").append(preCompHeaderOut + Option::dir_sep + "c");
291 project->values("QMAKE_CLEAN").append(preCompHeaderOut + Option::dir_sep + "c++");
292
293 project->values("QMAKE_RUN_CC").clear();
294 project->values("QMAKE_RUN_CC").append("$(CC) -c -include " + preCompHeader +
295 " $(CFLAGS) $(INCPATH) -o $obj $src");
296 project->values("QMAKE_RUN_CC_IMP").clear();
297 project->values("QMAKE_RUN_CC_IMP").append("$(CC) -c -include " + preCompHeader +
298 " $(CFLAGS) $(INCPATH) -o $@ $<");
299 project->values("QMAKE_RUN_CXX").clear();
300 project->values("QMAKE_RUN_CXX").append("$(CXX) -c -include " + preCompHeader +
301 " $(CXXFLAGS) $(INCPATH) -o $obj $src");
302 project->values("QMAKE_RUN_CXX_IMP").clear();
303 project->values("QMAKE_RUN_CXX_IMP").append("$(CXX) -c -include " + preCompHeader +
304 " $(CXXFLAGS) $(INCPATH) -o $@ $<");
305 }
306
307 if(project->isActiveConfig("dll")) {
308 project->values("QMAKE_CLEAN").append(project->first("MINGW_IMPORT_LIB"));
309 }
310}
311
312void MingwMakefileGenerator::fixTargetExt()
313{
314 if (project->isActiveConfig("staticlib") && project->first("TEMPLATE") == "lib") {
315 project->values("TARGET_EXT").append(".a");
316 project->values("QMAKE_LFLAGS").append("-static");
317 project->values("TARGET").first() = "lib" + project->first("TARGET");
318 } else {
319 Win32MakefileGenerator::fixTargetExt();
320 }
321}
322
323void MingwMakefileGenerator::writeIncPart(QTextStream &t)
324{
325 t << "INCPATH = ";
326
327 QStringList &incs = project->values("INCLUDEPATH");
328 for(QStringList::Iterator incit = incs.begin(); incit != incs.end(); ++incit) {
329 QString inc = (*incit);
330 inc.replace(QRegExp("\\\\$"), "");
331 inc.replace(QRegExp("\""), "");
332 t << "-I" << quote << inc << quote << " ";
333 }
334 t << "-I" << quote << specdir() << quote
335 << endl;
336}
337
338void MingwMakefileGenerator::writeLibsPart(QTextStream &t)
339{
340 if(project->isActiveConfig("staticlib") && project->first("TEMPLATE") == "lib") {
341 t << "LIB = " << var("QMAKE_LIB") << endl;
342 } else {
343 t << "LINK = " << var("QMAKE_LINK") << endl;
344 t << "LFLAGS = " << var("QMAKE_LFLAGS") << endl;
345 t << "LIBS = ";
346 if(!project->values("QMAKE_LIBDIR").isEmpty())
347 writeLibDirPart(t);
348 t << var("QMAKE_LIBS").replace(QRegExp("(\\slib|^lib)")," -l") << ' '
349 << var("QMAKE_LIBS_PRIVATE").replace(QRegExp("(\\slib|^lib)")," -l") << endl;
350 }
351}
352
353void MingwMakefileGenerator::writeLibDirPart(QTextStream &t)
354{
355 QStringList libDirs = project->values("QMAKE_LIBDIR");
356 for (int i = 0; i < libDirs.size(); ++i)
357 libDirs[i].remove("\"");
358 t << valGlue(libDirs,"-L"+quote,quote+" -L" +quote,quote) << " ";
359}
360
361void MingwMakefileGenerator::writeObjectsPart(QTextStream &t)
362{
363 if (project->values("OBJECTS").count() < var("QMAKE_LINK_OBJECT_MAX").toInt()) {
364 objectsLinkLine = "$(OBJECTS)";
365 } else if (project->isActiveConfig("staticlib") && project->first("TEMPLATE") == "lib") {
366 QString ar_script_file = var("QMAKE_LINK_OBJECT_SCRIPT") + "." + var("TARGET");
367 if (!var("BUILD_NAME").isEmpty()) {
368 ar_script_file += "." + var("BUILD_NAME");
369 }
370 createArObjectScriptFile(ar_script_file, var("DEST_TARGET"), project->values("OBJECTS"));
371 // QMAKE_LIB is used for win32, including mingw, whereas QMAKE_AR is used on Unix.
372 // Strip off any options since the ar commands will be read from file.
373 QString ar_cmd = var("QMAKE_LIB").section(" ", 0, 0);;
374 if (ar_cmd.isEmpty())
375 ar_cmd = "ar";
376 objectsLinkLine = ar_cmd + " -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 << " $(DEFINES)" << 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.