1 /****************************************************************************
2 ** $Id: qt/msvc_nmake.cpp   3.3.8   edited Jan 11 14:37 $
3 **
4 ** Implementation of NmakeMakefileGenerator class.
5 **
6 ** Copyright (C) 1992-2007 Trolltech ASA.  All rights reserved.
7 **
8 ** This file is part of qmake.
9 **
10 ** This file may be distributed under the terms of the Q Public License
11 ** as defined by Trolltech ASA of Norway and appearing in the file
12 ** LICENSE.QPL included in the packaging of this file.
13 **
14 ** This file may be distributed and/or modified under the terms of the
15 ** GNU General Public License version 2 as published by the Free Software
16 ** Foundation and appearing in the file LICENSE.GPL included in the
17 ** packaging of this file.
18 **
19 ** Licensees holding valid Qt Enterprise Edition licenses may use this
20 ** file in accordance with the Qt Commercial License Agreement provided
21 ** with the Software.
22 **
23 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
24 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
25 **
26 ** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
27 **   information about Qt Commercial License Agreements.
28 ** See http://www.trolltech.com/qpl/ for QPL licensing information.
29 ** See http://www.trolltech.com/gpl/ for GPL licensing information.
30 **
31 ** Contact info@trolltech.com if any conditions of this licensing are
32 ** not clear to you.
33 **
34 **********************************************************************/
35 
36 #include "msvc_nmake.h"
37 #include "option.h"
38 #include <qregexp.h>
39 #include <qdict.h>
40 #include <qdir.h>
41 #include <stdlib.h>
42 #include <time.h>
43 
NmakeMakefileGenerator(QMakeProject * p)44 NmakeMakefileGenerator::NmakeMakefileGenerator(QMakeProject *p) : Win32MakefileGenerator(p), init_flag(FALSE)
45 {
46 
47 }
48 
49 bool
writeMakefile(QTextStream & t)50 NmakeMakefileGenerator::writeMakefile(QTextStream &t)
51 {
52     writeHeader(t);
53     if(!project->variables()["QMAKE_FAILED_REQUIREMENTS"].isEmpty()) {
54 	{ //write the extra unix targets..
55 	    QStringList &qut = project->variables()["QMAKE_EXTRA_WIN_TARGETS"];
56 	    for(QStringList::ConstIterator it = qut.begin(); it != qut.end(); ++it)
57 		t << *it << " ";
58 	}
59 	t << "all clean:" << "\n\t"
60 	  << "@echo \"Some of the required modules ("
61 	  << var("QMAKE_FAILED_REQUIREMENTS") << ") are not available.\"" << "\n\t"
62 	  << "@echo \"Skipped.\"" << endl << endl;
63 	writeMakeQmake(t);
64 	return TRUE;
65     }
66 
67     if(project->first("TEMPLATE") == "app" ||
68        project->first("TEMPLATE") == "lib") {
69 	writeNmakeParts(t);
70 	return MakefileGenerator::writeMakefile(t);
71     }
72     else if(project->first("TEMPLATE") == "subdirs") {
73 	writeSubDirs(t);
74 	return TRUE;
75     }
76     return FALSE;
77 }
78 
79 QStringList
findDependencies(const QString & file)80 &NmakeMakefileGenerator::findDependencies(const QString &file)
81 {
82     QStringList &aList = MakefileGenerator::findDependencies(file);
83     // Note: The QMAKE_IMAGE_COLLECTION file have all images
84     // as dependency, so don't add precompiled header then
85     if (file == project->first("QMAKE_IMAGE_COLLECTION"))
86 	return aList;
87     for(QStringList::Iterator it = Option::cpp_ext.begin(); it != Option::cpp_ext.end(); ++it) {
88 	if(file.endsWith(*it)) {
89             if(!precompObj.isEmpty() && !aList.contains(precompObj))
90                 aList += precompObj;
91 	    break;
92 	}
93     }
94     return aList;
95 }
96 
97 void
writeNmakeParts(QTextStream & t)98 NmakeMakefileGenerator::writeNmakeParts(QTextStream &t)
99 {
100     t << "####### Compiler, tools and options" << endl << endl;
101     t << "CC		=	" << var("QMAKE_CC") << endl;
102     t << "CXX		=	" << var("QMAKE_CXX") << endl;
103     t << "LEX		= " << var("QMAKE_LEX") << endl;
104     t << "YACC		= " << var("QMAKE_YACC") << endl;
105     t << "CFLAGS	=	" << var("QMAKE_CFLAGS") << " "
106       << varGlue("PRL_EXPORT_DEFINES","-D"," -D","") << " "
107       <<  varGlue("DEFINES","-D"," -D","") << endl;
108     t << "CXXFLAGS	=	" << var("QMAKE_CXXFLAGS") << " "
109       << varGlue("PRL_EXPORT_DEFINES","-D"," -D","") << " "
110       << varGlue("DEFINES","-D"," -D","") << endl;
111     t << "LEXFLAGS	=" << var("QMAKE_LEXFLAGS") << endl;
112     t << "YACCFLAGS	=" << var("QMAKE_YACCFLAGS") << endl;
113 
114     t << "INCPATH	=	";
115     QStringList &incs = project->variables()["INCLUDEPATH"];
116     for(QStringList::Iterator incit = incs.begin(); incit != incs.end(); ++incit) {
117 	QString inc = (*incit);
118 	if (inc.endsWith("\\"))
119 	    inc.truncate(inc.length()-1);
120 	if (inc.startsWith("\"") && inc.endsWith("\""))
121 	    inc = inc.mid(1, inc.length() - 2);
122 	t << " -I\"" << inc << "\"";
123     }
124     t << " -I\"" << specdir() << "\""
125       << endl;
126     if(!project->variables()["QMAKE_APP_OR_DLL"].isEmpty()) {
127 	t << "LINK	=	" << var("QMAKE_LINK") << endl;
128 	t << "LFLAGS	=	" << var("QMAKE_LFLAGS");
129 	if ( !project->variables()["QMAKE_LIBDIR"].isEmpty() )
130 	  t << " " << varGlue("QMAKE_LIBDIR","/LIBPATH:\"","\" /LIBPATH:\"","\"");
131 	t << endl;
132 	t << "LIBS	=	";
133 	QStringList &libs = project->variables()["QMAKE_LIBS"];
134 	for(QStringList::Iterator libit = libs.begin(); libit != libs.end(); ++libit) {
135 	    QString lib = (*libit);
136 	    if (lib.endsWith("\\"))
137 		lib.truncate(lib.length()-1);
138 	    t << " \"" << lib << "\"";
139 	}
140 	t << endl;
141     }
142     else {
143 	t << "LIB	=	" << var("QMAKE_LIB") << endl;
144     }
145     t << "MOC		=	" << (project->isEmpty("QMAKE_MOC") ? QString("moc") :
146 			      Option::fixPathToTargetOS(var("QMAKE_MOC"), FALSE)) << endl;
147     t << "UIC		=	" << (project->isEmpty("QMAKE_UIC") ? QString("uic") :
148 			      Option::fixPathToTargetOS(var("QMAKE_UIC"), FALSE)) << endl;
149     t << "QMAKE		=	" << (project->isEmpty("QMAKE_QMAKE") ? QString("qmake") :
150 			      Option::fixPathToTargetOS(var("QMAKE_QMAKE"), FALSE)) << endl;
151     t << "IDC		=	" << (project->isEmpty("QMAKE_IDC") ? QString("idc") :
152 			      Option::fixPathToTargetOS(var("QMAKE_IDC"), FALSE)) << endl;
153     t << "IDL		=	" << (project->isEmpty("QMAKE_IDL") ? QString("midl") :
154 			      Option::fixPathToTargetOS(var("QMAKE_IDL"), FALSE)) << endl;
155     t << "ZIP		=	" << var("QMAKE_ZIP") << endl;
156     t << "COPY_FILE	=       " << var("QMAKE_COPY") << endl;
157     t << "COPY_DIR	=       " << var("QMAKE_COPY") << endl;
158     t << "DEL_FILE	=       " << var("QMAKE_DEL_FILE") << endl;
159     t << "DEL_DIR	=       " << var("QMAKE_DEL_DIR") << endl;
160     t << "MOVE		=       " << var("QMAKE_MOVE") << endl;
161     t << "CHK_DIR_EXISTS =	" << var("QMAKE_CHK_DIR_EXISTS") << endl;
162     t << "MKDIR		=	" << var("QMAKE_MKDIR") << endl;
163     t << "INSTALL_FILE= " << var("QMAKE_INSTALL_FILE") << endl;
164     t << "INSTALL_DIR = " << var("QMAKE_INSTALL_DIR") << endl;
165     t << endl;
166 
167     t << "####### Files" << endl << endl;
168     t << "HEADERS =	" << varList("HEADERS") << endl;
169     t << "SOURCES =	" << varList("SOURCES") << endl;
170     t << "OBJECTS =	" << varList("OBJECTS") << endl;
171     t << "FORMS =	" << varList("FORMS") << endl;
172     t << "UICDECLS =	" << varList("UICDECLS") << endl;
173     t << "UICIMPLS =	" << varList("UICIMPLS") << endl;
174     t << "SRCMOC	=	" << varList("SRCMOC") << endl;
175     t << "OBJMOC	=	" << varList("OBJMOC") << endl;
176 
177     QString extraCompilerDeps;
178     if(!project->isEmpty("QMAKE_EXTRA_WIN_COMPILERS")) {
179 	t << "OBJCOMP = " << varList("OBJCOMP") << endl;
180 	extraCompilerDeps += " $(OBJCOMP) ";
181 
182 	QStringList &comps = project->variables()["QMAKE_EXTRA_WIN_COMPILERS"];
183 	for(QStringList::Iterator compit = comps.begin(); compit != comps.end(); ++compit) {
184 	    QStringList &vars = project->variables()[(*compit) + ".variables"];
185 	    for(QStringList::Iterator varit = vars.begin(); varit != vars.end(); ++varit) {
186 		QStringList vals = project->variables()[(*varit)];
187 		if(!vals.isEmpty())
188 		    t << "QMAKE_COMP_" << (*varit) << " = " << valList(vals) << endl;
189 	    }
190 	}
191     }
192 
193     t << "DIST	=	" << varList("DISTFILES") << endl;
194     t << "TARGET	=	";
195     if( !project->variables()[ "DESTDIR" ].isEmpty() )
196 	t << varGlue("TARGET",project->first("DESTDIR"),"",project->first("TARGET_EXT"));
197     else
198 	t << project->variables()[ "TARGET" ].first() << project->variables()[ "TARGET_EXT" ].first();
199     t << endl;
200     t << endl;
201 
202     t << "####### Implicit rules" << endl << endl;
203     t << ".SUFFIXES: .c";
204     QStringList::Iterator cppit;
205     for(cppit = Option::cpp_ext.begin(); cppit != Option::cpp_ext.end(); ++cppit)
206 	t << " " << (*cppit);
207     t << endl << endl;
208 
209     if(!project->isActiveConfig("no_batch")) {
210 	// Batchmode doesn't use the non implicit rules QMAKE_RUN_CXX & QMAKE_RUN_CC
211 	project->variables().remove("QMAKE_RUN_CXX");
212 	project->variables().remove("QMAKE_RUN_CC");
213 
214 	QDict<void> source_directories;
215 	source_directories.insert(".", (void*)1);
216 	QString directories[] = { QString("MOC_DIR"), QString("UI_SOURCES_DIR"), QString("UI_DIR"), QString::null };
217 	for(int y = 0; !directories[y].isNull(); y++) {
218 	    QString dirTemp = project->first(directories[y]);
219 	    if (dirTemp.endsWith("\\"))
220 		dirTemp.truncate(dirTemp.length()-1);
221 	    if(!dirTemp.isEmpty())
222 		source_directories.insert(dirTemp, (void*)1);
223 	}
224 	QString srcs[] = { QString("SOURCES"), QString("UICIMPLS"), QString("SRCMOC"), QString::null };
225 	for(int x = 0; !srcs[x].isNull(); x++) {
226 	    QStringList &l = project->variables()[srcs[x]];
227 	    for(QStringList::Iterator sit = l.begin(); sit != l.end(); ++sit) {
228 		QString sep = "\\";
229 		if((*sit).find(sep) == -1)
230 		    sep = "/";
231 		QString dir = (*sit).section(sep, 0, -2);
232 		if(!dir.isEmpty() && !source_directories[dir])
233 		    source_directories.insert(dir, (void*)1);
234 	    }
235 	}
236 
237 	for(QDictIterator<void> it(source_directories); it.current(); ++it) {
238 	    if(it.currentKey().isEmpty())
239 		continue;
240 	    for(cppit = Option::cpp_ext.begin(); cppit != Option::cpp_ext.end(); ++cppit)
241 		t << "{" << it.currentKey() << "}" << (*cppit) << "{" << var("OBJECTS_DIR") << "}" << Option::obj_ext << "::\n\t"
242 		  << var("QMAKE_RUN_CXX_IMP_BATCH").replace( QRegExp( "\\$@" ), var("OBJECTS_DIR") ) << endl << "\t$<" << endl << "<<" << endl << endl;
243 	    t << "{" << it.currentKey() << "}" << ".c{" << var("OBJECTS_DIR") << "}" << Option::obj_ext << "::\n\t"
244 	      << var("QMAKE_RUN_CC_IMP_BATCH").replace( QRegExp( "\\$@" ), var("OBJECTS_DIR") ) << endl << "\t$<" << endl << "<<" << endl << endl;
245 	}
246     } else {
247 	for(cppit = Option::cpp_ext.begin(); cppit != Option::cpp_ext.end(); ++cppit)
248 	    t << (*cppit) << Option::obj_ext << ":\n\t" << var("QMAKE_RUN_CXX_IMP") << endl << endl;
249 	t << ".c" << Option::obj_ext << ":\n\t" << var("QMAKE_RUN_CC_IMP") << endl << endl;
250     }
251 
252     t << "####### Build rules" << endl << endl;
253     t << "all: " << fileFixify(Option::output.name()) << " " << varGlue("ALL_DEPS"," "," "," ") << "$(TARGET)" << endl << endl;
254     t << "$(TARGET): " << var("PRE_TARGETDEPS") << " $(UICDECLS) $(OBJECTS) $(OBJMOC) "
255       << extraCompilerDeps << var("POST_TARGETDEPS");
256     if(!project->variables()["QMAKE_APP_OR_DLL"].isEmpty()) {
257 	t << "\n\t" << "$(LINK) $(LFLAGS) /OUT:$(TARGET) @<< " << "\n\t  "
258 	  << "$(OBJECTS) $(OBJMOC) $(LIBS)";
259     } else {
260 	t << "\n\t" << "$(LIB) /OUT:$(TARGET) @<<" << "\n\t  "
261 	  << "$(OBJECTS) $(OBJMOC)";
262     }
263     t << extraCompilerDeps;
264     t << endl << "<<" << endl;
265     if ( !project->variables()["QMAKE_POST_LINK"].isEmpty() )
266 	t << "\t" << var( "QMAKE_POST_LINK" ) << endl;
267     if(project->isActiveConfig("dll") && !project->variables()["DLLDESTDIR"].isEmpty()) {
268 	QStringList dlldirs = project->variables()["DLLDESTDIR"];
269 	for ( QStringList::Iterator dlldir = dlldirs.begin(); dlldir != dlldirs.end(); ++dlldir ) {
270 	    t << "\n\t" << "-$(COPY_FILE) \"$(TARGET)\" " << *dlldir;
271 	}
272     }
273     QString targetfilename = project->variables()["TARGET"].first();
274     if(project->isActiveConfig("activeqt")) {
275 	QString version = project->variables()["VERSION"].first();
276 	if ( version.isEmpty() )
277 	    version = "1.0";
278 
279 	if ( project->isActiveConfig("dll")) {
280 	    t << "\n\t" << ("-$(IDC) $(TARGET) /idl " + var("OBJECTS_DIR") + targetfilename + ".idl -version " + version);
281 	    t << "\n\t" << ("-$(IDL) /nologo " + var("OBJECTS_DIR") + targetfilename + ".idl /tlb " + var("OBJECTS_DIR") + targetfilename + ".tlb");
282 	    t << "\n\t" << ("-$(IDC) $(TARGET) /tlb " + var("OBJECTS_DIR") + targetfilename + ".tlb");
283 	    t << "\n\t" << ("-$(IDC) $(TARGET) /regserver" );
284 	} else {
285 	    t << "\n\t" << ("-$(TARGET) -dumpidl " + var("OBJECTS_DIR") + targetfilename + ".idl -version " + version);
286 	    t << "\n\t" << ("-$(IDL) /nologo " + var("OBJECTS_DIR") + targetfilename + ".idl /tlb " + var("OBJECTS_DIR") + targetfilename + ".tlb");
287 	    t << "\n\t" << ("-$(IDC) $(TARGET) /tlb " + var("OBJECTS_DIR") + targetfilename + ".tlb");
288 	    t << "\n\t" << "-$(TARGET) -regserver";
289 	}
290     }
291     t << endl << endl;
292 
293     if(!project->variables()["RC_FILE"].isEmpty()) {
294 	t << var("RES_FILE") << ": " << var("RC_FILE") << "\n\t"
295 	  << var("QMAKE_RC") << " " << var("RC_FILE") << endl << endl;
296     }
297 
298     t << "mocables: $(SRCMOC)" << endl
299       << "uicables: $(UICIMPLS) $(UICDECLS)" << endl << endl;
300 
301     writeMakeQmake(t);
302 
303     QStringList dist_files = Option::mkfile::project_files;
304     if(!project->isEmpty("QMAKE_INTERNAL_INCLUDED_FILES"))
305 	dist_files += project->variables()["QMAKE_INTERNAL_INCLUDED_FILES"];
306     if(!project->isEmpty("TRANSLATIONS"))
307 	dist_files << var("TRANSLATIONS");
308     if(!project->isEmpty("FORMS")) {
309 	QStringList &forms = project->variables()["FORMS"];
310 	for(QStringList::Iterator formit = forms.begin(); formit != forms.end(); ++formit) {
311 	    QString ui_h = fileFixify((*formit) + Option::h_ext.first());
312 	    if(QFile::exists(ui_h) )
313 		dist_files << ui_h;
314 	}
315     }
316     t << "dist:" << "\n\t"
317       << "$(ZIP) " << var("QMAKE_ORIG_TARGET") << ".zip " << "$(SOURCES) $(HEADERS) $(DIST) $(FORMS) "
318       << dist_files.join(" ") << " " << var("TRANSLATIONS") << " " << var("IMAGES") << endl << endl;
319 
320     t << "uiclean:"
321       << varGlue("UICDECLS" ,"\n\t-$(DEL_FILE) ","\n\t-$(DEL_FILE) ","")
322       << varGlue("UICIMPLS" ,"\n\t-$(DEL_FILE) ","\n\t-$(DEL_FILE) ","") << endl;
323 
324     t << "mocclean:"
325       << varGlue("SRCMOC" ,"\n\t-$(DEL_FILE) ","\n\t-$(DEL_FILE) ","")
326       << varGlue("OBJMOC" ,"\n\t-$(DEL_FILE) ","\n\t-$(DEL_FILE) ","") << endl;
327 
328     t << "clean: uiclean mocclean"
329       << varGlue("OBJECTS","\n\t-$(DEL_FILE) ","\n\t-$(DEL_FILE) ","")
330       << varGlue("QMAKE_CLEAN","\n\t-$(DEL_FILE) ","\n\t-$(DEL_FILE) ","\n")
331       << varGlue("CLEAN_FILES","\n\t-$(DEL_FILE) ","\n\t-$(DEL_FILE) ","\n");
332     if ( project->isActiveConfig("activeqt")) {
333 	t << ("\n\t-$(DEL_FILE) " + var("OBJECTS_DIR") + targetfilename + ".idl");
334 	t << ("\n\t-$(DEL_FILE) " + var("OBJECTS_DIR") + targetfilename + ".tlb");
335     }
336     if(!project->isEmpty("IMAGES"))
337 	t << varGlue("QMAKE_IMAGE_COLLECTION", "\n\t-$(DEL_FILE) ", "\n\t-$(DEL_FILE) ", "");
338     t << endl;
339 
340     // user defined targets
341 
342     QStringList::Iterator it;
343     QStringList &qut = project->variables()["QMAKE_EXTRA_WIN_TARGETS"];
344     for(it = qut.begin(); it != qut.end(); ++it) {
345 	QString targ = var((*it) + ".target"),
346 		 cmd = var((*it) + ".commands"), deps;
347 	if(targ.isEmpty())
348 	    targ = (*it);
349 	QStringList &deplist = project->variables()[(*it) + ".depends"];
350 	for(QStringList::Iterator dep_it = deplist.begin(); dep_it != deplist.end(); ++dep_it) {
351 	    QString dep = var((*dep_it) + ".target");
352 	    if(dep.isEmpty())
353 		dep = (*dep_it);
354 	    deps += " " + dep;
355 	}
356 	if(!project->variables()["QMAKE_NOFORCE"].isEmpty() &&
357 	   project->variables()[(*it) + ".CONFIG"].findIndex("phony") != -1)
358 	    deps += QString(" ") + "FORCE";
359 	t << "\n\n" << targ << ":" << deps << "\n\t"
360 	  << cmd;
361     }
362     t << endl << endl;
363 
364     QStringList &quc = project->variables()["QMAKE_EXTRA_WIN_COMPILERS"];
365     for(it = quc.begin(); it != quc.end(); ++it) {
366 	QString tmp_out = project->variables()[(*it) + ".output"].first();
367 	QString tmp_cmd = project->variables()[(*it) + ".commands"].join(" ");
368 	QString tmp_dep = project->variables()[(*it) + ".depends"].join(" ");
369 	QStringList &vars = project->variables()[(*it) + ".variables"];
370 	if(tmp_out.isEmpty() || tmp_cmd.isEmpty())
371 	    continue;
372 	QStringList &tmp = project->variables()[(*it) + ".input"];
373 	for(QStringList::Iterator it2 = tmp.begin(); it2 != tmp.end(); ++it2) {
374 	    QStringList &inputs = project->variables()[(*it2)];
375 	    for(QStringList::Iterator input = inputs.begin(); input != inputs.end(); ++input) {
376 		QFileInfo fi(Option::fixPathToLocalOS((*input)));
377 		QString in = Option::fixPathToTargetOS((*input), FALSE),
378 		       out = tmp_out, cmd = tmp_cmd, deps;
379 		out.replace("${QMAKE_FILE_BASE}", fi.baseName());
380 		out.replace("${QMAKE_FILE_NAME}", fi.filePath());
381 		cmd.replace("${QMAKE_FILE_BASE}", fi.baseName());
382 		cmd.replace("${QMAKE_FILE_OUT}", out);
383 		cmd.replace("${QMAKE_FILE_NAME}", fi.filePath());
384 		for(QStringList::Iterator it3 = vars.begin(); it3 != vars.end(); ++it3)
385 		    cmd.replace("$(" + (*it3) + ")", "$(QMAKE_COMP_" + (*it3)+")");
386 		if(!tmp_dep.isEmpty()) {
387 		    char buff[256];
388 		    QString dep_cmd = tmp_dep;
389 		    dep_cmd.replace("${QMAKE_FILE_NAME}", fi.filePath());
390 		    if(FILE *proc = QT_POPEN(dep_cmd.latin1(), "r")) {
391 			while(!feof(proc)) {
392 			    int read_in = int(fread(buff, 1, 255, proc));
393 			    if(!read_in)
394 				break;
395 			    int l = 0;
396 			    for(int i = 0; i < read_in; i++) {
397 				if(buff[i] == '\n' || buff[i] == ' ') {
398 				    deps += " " + QCString(buff+l, (i - l) + 1);
399 				    l = i;
400 				}
401 			    }
402 			}
403 			fclose(proc);
404 		    }
405 		}
406 		t << out << ": " << in << deps << "\n\t"
407 		  << cmd << endl << endl;
408 	    }
409 	}
410     }
411     t << endl;
412 
413     if(project->variables()["QMAKE_NOFORCE"].isEmpty())
414 	t << "FORCE:" << endl << endl;
415 
416     t << "distclean: clean"
417       << "\n\t-$(DEL_FILE) $(TARGET)"
418       << endl << endl;
419 
420     // precompiled header
421     if(usePCH) {
422 	QString precompRule = QString("-c -Yc -Fp%1 -Fo%2").arg(precompPch).arg(precompObj);
423 	t << precompObj << ": " << precompH << " " << findDependencies(precompH).join(" \\\n\t\t")
424 	  << "\n\t" << ("$(CXX) " + precompRule + " $(CXXFLAGS) $(INCPATH) -TP ") << precompH << endl << endl;
425     }
426 }
427 
428 QString
var(const QString & value)429 NmakeMakefileGenerator::var(const QString &value)
430 {
431     if (usePCH) {
432     	if ((value == "QMAKE_RUN_CXX_IMP_BATCH"
433 	    || value == "QMAKE_RUN_CXX_IMP"
434 	    || value == "QMAKE_RUN_CXX")) {
435 	    QFileInfo precompHInfo(precompH);
436 	    QString precompRule = QString("-c -FI%1 -Yu%2 -Fp%3")
437 		.arg(precompHInfo.fileName())
438 		.arg(precompHInfo.fileName())
439 		.arg(precompPch);
440 	    QString p = MakefileGenerator::var(value);
441 	    p.replace("-c", precompRule);
442 	    // Cannot use -Gm with -FI & -Yu, as this gives an
443 	    // internal compiler error, on the newer compilers
444 	    p.remove("-Gm");
445 	    return p;
446 	} else if (value == "QMAKE_CXXFLAGS") {
447 	    // Remove internal compiler error option
448 	    return MakefileGenerator::var(value).remove("-Gm");
449 	}
450     }
451 
452     // Normal val
453     return MakefileGenerator::var(value);
454 }
455 
456 void
init()457 NmakeMakefileGenerator::init()
458 {
459     if(init_flag)
460 	return;
461     init_flag = TRUE;
462 
463     /* this should probably not be here, but I'm using it to wrap the .t files */
464     if(project->first("TEMPLATE") == "app")
465 	project->variables()["QMAKE_APP_FLAG"].append("1");
466     else if(project->first("TEMPLATE") == "lib")
467 	project->variables()["QMAKE_LIB_FLAG"].append("1");
468     else if(project->first("TEMPLATE") == "subdirs") {
469 	MakefileGenerator::init();
470 	if(project->variables()["MAKEFILE"].isEmpty())
471 	    project->variables()["MAKEFILE"].append("Makefile");
472 	if(project->variables()["QMAKE"].isEmpty())
473 	    project->variables()["QMAKE"].append("qmake");
474 	return;
475     }
476 
477     if(project->isEmpty("QMAKE_INSTALL_FILE"))
478 	project->variables()["QMAKE_INSTALL_FILE"].append("$(COPY_FILE)");
479     if(project->isEmpty("QMAKE_INSTALL_DIR"))
480 	project->variables()["QMAKE_INSTALL_DIR"].append("$(COPY_DIR)");
481 
482     bool is_qt = (project->first("TARGET") == "qt" QTDLL_POSTFIX || project->first("TARGET") == "qt-mt" QTDLL_POSTFIX);
483     project->variables()["QMAKE_ORIG_TARGET"] = project->variables()["TARGET"];
484 
485     QString targetfilename = project->variables()["TARGET"].first();
486     QStringList &configs = project->variables()["CONFIG"];
487     if (project->isActiveConfig("qt") && project->isActiveConfig("shared"))
488 	project->variables()["DEFINES"].append("QT_DLL");
489     if (project->isActiveConfig("qt_dll"))
490 	if(configs.findIndex("qt") == -1) configs.append("qt");
491     if ( project->isActiveConfig("qtopia") ) {
492 	if(configs.findIndex("qtopialib") == -1)
493 	    configs.append("qtopialib");
494 	if(configs.findIndex("qtopiainc") == -1)
495 	    configs.append("qtopiainc");
496     }
497     if ( project->isActiveConfig("qt") ) {
498 	if ( project->isActiveConfig( "plugin" ) ) {
499 	    project->variables()["CONFIG"].append("dll");
500 	    if(project->isActiveConfig("qt"))
501 		project->variables()["DEFINES"].append("QT_PLUGIN");
502 	}
503 	if ( (project->variables()["DEFINES"].findIndex("QT_NODLL") == -1) &&
504          ((project->variables()["DEFINES"].findIndex("QT_MAKEDLL") != -1 ||
505            project->variables()["DEFINES"].findIndex("QT_DLL") != -1) ||
506           (getenv("QT_DLL") && !getenv("QT_NODLL"))) ) {
507 	    project->variables()["QMAKE_QT_DLL"].append("1");
508 	    if ( is_qt && !project->variables()["QMAKE_LIB_FLAG"].isEmpty() )
509 		project->variables()["CONFIG"].append("dll");
510 	}
511 	if ( project->isActiveConfig("thread") )
512 	    project->variables()[is_qt ? "PRL_EXPORT_DEFINES" : "DEFINES"].append("QT_THREAD_SUPPORT");
513 	if ( project->isActiveConfig("accessibility" ) )
514 	    project->variables()[is_qt ? "PRL_EXPORT_DEFINES" : "DEFINES"].append("QT_ACCESSIBILITY_SUPPORT");
515 	if ( project->isActiveConfig("tablet") )
516 	    project->variables()[is_qt ? "PRL_EXPORT_DEFINES" : "DEFINES"].append("QT_TABLET_SUPPORT");
517     }
518     if ( project->isActiveConfig("dll") || !project->variables()["QMAKE_APP_FLAG"].isEmpty() ) {
519 	project->variables()["CONFIG"].remove("staticlib");
520 	project->variables()["QMAKE_APP_OR_DLL"].append("1");
521     } else {
522 	project->variables()["CONFIG"].append("staticlib");
523     }
524     if ( project->isActiveConfig("warn_off") ) {
525 	project->variables()["QMAKE_CFLAGS"] += project->variables()["QMAKE_CFLAGS_WARN_OFF"];
526 	project->variables()["QMAKE_CXXFLAGS"] += project->variables()["QMAKE_CXXFLAGS_WARN_OFF"];
527     } else if ( project->isActiveConfig("warn_on") ) {
528 	project->variables()["QMAKE_CFLAGS"] += project->variables()["QMAKE_CFLAGS_WARN_ON"];
529 	project->variables()["QMAKE_CXXFLAGS"] += project->variables()["QMAKE_CXXFLAGS_WARN_ON"];
530     }
531     if ( project->isActiveConfig("debug") ) {
532         if ( project->isActiveConfig("thread") ) {
533 	    // use the DLL RT even here
534 	    if ( project->variables()["DEFINES"].contains("QT_DLL") ) {
535 		project->variables()["QMAKE_CFLAGS"] += project->variables()["QMAKE_CFLAGS_MT_DLLDBG"];
536 		project->variables()["QMAKE_CXXFLAGS"] += project->variables()["QMAKE_CXXFLAGS_MT_DLLDBG"];
537 	    } else {
538 		project->variables()["QMAKE_CFLAGS"] += project->variables()["QMAKE_CFLAGS_MT_DBG"];
539 		project->variables()["QMAKE_CXXFLAGS"] += project->variables()["QMAKE_CXXFLAGS_MT_DBG"];
540 	    }
541 	}
542 	project->variables()["QMAKE_CFLAGS"] += project->variables()["QMAKE_CFLAGS_DEBUG"];
543 	project->variables()["QMAKE_CXXFLAGS"] += project->variables()["QMAKE_CXXFLAGS_DEBUG"];
544 	project->variables()["QMAKE_LFLAGS"] += project->variables()["QMAKE_LFLAGS_DEBUG"];
545     } else {
546 	if ( project->isActiveConfig("thread") ) {
547 	    if ( project->variables()["DEFINES"].contains("QT_DLL") ) {
548 		project->variables()["QMAKE_CFLAGS"] += project->variables()["QMAKE_CFLAGS_MT_DLL"];
549 		project->variables()["QMAKE_CXXFLAGS"] += project->variables()["QMAKE_CXXFLAGS_MT_DLL"];
550 	    } else {
551 		project->variables()["QMAKE_CFLAGS"] += project->variables()["QMAKE_CFLAGS_MT"];
552 		project->variables()["QMAKE_CXXFLAGS"] += project->variables()["QMAKE_CXXFLAGS_MT"];
553 	    }
554 	}
555 	project->variables()["QMAKE_CFLAGS"] += project->variables()["QMAKE_CFLAGS_RELEASE"];
556 	project->variables()["QMAKE_CXXFLAGS"] += project->variables()["QMAKE_CXXFLAGS_RELEASE"];
557 	project->variables()["QMAKE_LFLAGS"] += project->variables()["QMAKE_LFLAGS_RELEASE"];
558     }
559     if ( project->isActiveConfig("thread") && !project->variables()["DEFINES"].contains("QT_DLL")
560 	&& !is_qt && project->first("TARGET") != "qtmain") {
561 	project->variables()["QMAKE_LFLAGS"].append("/NODEFAULTLIB:\"libc\"");
562     }
563 
564     if ( !project->variables()["QMAKE_INCDIR"].isEmpty())
565 	project->variables()["INCLUDEPATH"] += project->variables()["QMAKE_INCDIR"];
566     if ( project->isActiveConfig("qt") || project->isActiveConfig("opengl") )
567 	project->variables()["CONFIG"].append("windows");
568     if ( project->isActiveConfig("qtopiainc") )
569 	project->variables()["INCLUDEPATH"] += project->variables()["QMAKE_INCDIR_QTOPIA"];
570     if ( project->isActiveConfig("qtopialib") ) {
571 	if(!project->isEmpty("QMAKE_LIBDIR_QTOPIA"))
572 	    project->variables()["QMAKE_LIBDIR"] += project->variables()["QMAKE_LIBDIR_QTOPIA"];
573 	project->variables()["QMAKE_LIBS"] += project->variables()["QMAKE_LIBS_QTOPIA"];
574     }
575     if ( project->isActiveConfig("qt") ) {
576 	project->variables()["CONFIG"].append("moc");
577 	project->variables()["INCLUDEPATH"] +=	project->variables()["QMAKE_INCDIR_QT"];
578 	project->variables()["QMAKE_LIBDIR"] += project->variables()["QMAKE_LIBDIR_QT"];
579 	if ( !project->isActiveConfig("debug") )
580 	    project->variables()[is_qt ? "PRL_EXPORT_DEFINES" : "DEFINES"].append("QT_NO_DEBUG");
581 	if ( is_qt && !project->variables()["QMAKE_LIB_FLAG"].isEmpty() ) {
582 	    if ( !project->variables()["QMAKE_QT_DLL"].isEmpty()) {
583 		project->variables()["DEFINES"].append("QT_MAKEDLL");
584 		project->variables()["QMAKE_LFLAGS"] += project->variables()["QMAKE_LFLAGS_QT_DLL"];
585 	    }
586 	} else {
587 	    if(project->isActiveConfig("thread"))
588 		project->variables()["QMAKE_LIBS"] += project->variables()["QMAKE_LIBS_QT_THREAD"];
589 	    else
590 		project->variables()["QMAKE_LIBS"] += project->variables()["QMAKE_LIBS_QT"];
591 	    if ( !project->variables()["QMAKE_QT_DLL"].isEmpty() ) {
592 		int hver = findHighestVersion(project->first("QMAKE_LIBDIR_QT"), "qt");
593 		if ( hver == -1 )
594 		    hver = findHighestVersion(project->first("QMAKE_LIBDIR_QT"), "qt-mt");
595 		if(hver != -1) {
596 		    QString ver;
597 		    ver.sprintf("qt%s" QTDLL_POSTFIX "%d.lib", (project->isActiveConfig("thread") ? "-mt" : ""), hver);
598 		    QStringList &libs = project->variables()["QMAKE_LIBS"];
599 		    for(QStringList::Iterator libit = libs.begin(); libit != libs.end(); ++libit)
600 			(*libit).replace(QRegExp("qt(-mt)?\\.lib"), ver);
601 		}
602 	    }
603 	    if ( project->isActiveConfig( "activeqt" ) ) {
604 		project->variables().remove("QMAKE_LIBS_QT_ENTRY");
605 		project->variables()["QMAKE_LIBS_QT_ENTRY"] = "qaxserver.lib";
606 		if ( project->isActiveConfig( "dll" ) )
607 		    project->variables()["QMAKE_LIBS"] += project->variables()["QMAKE_LIBS_QT_ENTRY"];
608 	    }
609 	    if ( !project->isActiveConfig("dll") && !project->isActiveConfig("plugin") ) {
610 		project->variables()["QMAKE_LIBS"] +=project->variables()["QMAKE_LIBS_QT_ENTRY"];
611 	    }
612 	}
613     }
614     if ( project->isActiveConfig("opengl") ) {
615 	project->variables()["QMAKE_LIBS"] += project->variables()["QMAKE_LIBS_OPENGL"];
616 	project->variables()["QMAKE_LFLAGS"] += project->variables()["QMAKE_LFLAGS_OPENGL"];
617     }
618     if ( project->isActiveConfig("dll") ) {
619 	project->variables()["QMAKE_CFLAGS_CONSOLE_ANY"] = project->variables()["QMAKE_CFLAGS_CONSOLE_DLL"];
620 	project->variables()["QMAKE_CXXFLAGS_CONSOLE_ANY"] = project->variables()["QMAKE_CXXFLAGS_CONSOLE_DLL"];
621 	project->variables()["QMAKE_LFLAGS_CONSOLE_ANY"] = project->variables()["QMAKE_LFLAGS_CONSOLE_DLL"];
622 	project->variables()["QMAKE_LFLAGS_WINDOWS_ANY"] = project->variables()["QMAKE_LFLAGS_WINDOWS_DLL"];
623 	if ( !project->variables()["QMAKE_LIB_FLAG"].isEmpty()) {
624 	    project->variables()["TARGET_EXT"].append(
625 		QStringList::split('.',project->first("VERSION")).join("") + ".dll");
626 	} else {
627 	    project->variables()["TARGET_EXT"].append(".dll");
628 	}
629     } else {
630 	project->variables()["QMAKE_CFLAGS_CONSOLE_ANY"] = project->variables()["QMAKE_CFLAGS_CONSOLE"];
631 	project->variables()["QMAKE_CXXFLAGS_CONSOLE_ANY"] = project->variables()["QMAKE_CXXFLAGS_CONSOLE"];
632 	project->variables()["QMAKE_LFLAGS_CONSOLE_ANY"] = project->variables()["QMAKE_LFLAGS_CONSOLE"];
633 	project->variables()["QMAKE_LFLAGS_WINDOWS_ANY"] = project->variables()["QMAKE_LFLAGS_WINDOWS"];
634 	if ( !project->variables()["QMAKE_APP_FLAG"].isEmpty()) {
635 	    project->variables()["TARGET_EXT"].append(".exe");
636 	} else {
637 	    project->variables()["TARGET_EXT"].append(".lib");
638 	}
639     }
640     if ( project->isActiveConfig("windows") ) {
641 	if ( project->isActiveConfig("console") ) {
642 	    project->variables()["QMAKE_CFLAGS"] += project->variables()["QMAKE_CFLAGS_CONSOLE_ANY"];
643 	    project->variables()["QMAKE_CXXFLAGS"] += project->variables()["QMAKE_CXXFLAGS_CONSOLE_ANY"];
644 	    project->variables()["QMAKE_LFLAGS"] += project->variables()["QMAKE_LFLAGS_CONSOLE_ANY"];
645 	    project->variables()["QMAKE_LIBS"] += project->variables()["QMAKE_LIBS_CONSOLE"];
646 	} else {
647 	    project->variables()["QMAKE_LFLAGS"] += project->variables()["QMAKE_LFLAGS_WINDOWS_ANY"];
648 	}
649 	project->variables()["QMAKE_LIBS"] += project->variables()["QMAKE_LIBS_WINDOWS"];
650     } else {
651 	project->variables()["QMAKE_CFLAGS"] += project->variables()["QMAKE_CFLAGS_CONSOLE_ANY"];
652 	project->variables()["QMAKE_CXXFLAGS"] += project->variables()["QMAKE_CXXFLAGS_CONSOLE_ANY"];
653 	project->variables()["QMAKE_LFLAGS"] += project->variables()["QMAKE_LFLAGS_CONSOLE_ANY"];
654 	project->variables()["QMAKE_LIBS"] += project->variables()["QMAKE_LIBS_CONSOLE"];
655     }
656     if ( project->isActiveConfig("stl") ) {
657 	project->variables()["QMAKE_CFLAGS"] += project->variables()["QMAKE_CFLAGS_STL_ON"];
658 	project->variables()["QMAKE_CXXFLAGS"] += project->variables()["QMAKE_CXXFLAGS_STL_ON"];
659     } else {
660 	project->variables()["QMAKE_CFLAGS"] += project->variables()["QMAKE_CFLAGS_STL_OFF"];
661 	project->variables()["QMAKE_CXXFLAGS"] += project->variables()["QMAKE_CXXFLAGS_STL_OFF"];
662     }
663     if ( project->isActiveConfig("exceptions") ) {
664 	project->variables()["QMAKE_CFLAGS"] += project->variables()["QMAKE_CFLAGS_EXCEPTIONS_ON"];
665 	project->variables()["QMAKE_CXXFLAGS"] += project->variables()["QMAKE_CXXFLAGS_EXCEPTIONS_ON"];
666     } else {
667 	project->variables()["QMAKE_CFLAGS"] += project->variables()["QMAKE_CFLAGS_EXCEPTIONS_OFF"];
668 	project->variables()["QMAKE_CXXFLAGS"] += project->variables()["QMAKE_CXXFLAGS_EXCEPTIONS_OFF"];
669     }
670     if ( project->isActiveConfig("rtti") ) {
671 	project->variables()["QMAKE_CFLAGS"] += project->variables()["QMAKE_CFLAGS_RTTI_ON"];
672 	project->variables()["QMAKE_CXXFLAGS"] += project->variables()["QMAKE_CXXFLAGS_RTTI_ON"];
673     } else {
674 	project->variables()["QMAKE_CFLAGS"] += project->variables()["QMAKE_CFLAGS_RTTI_OFF"];
675 	project->variables()["QMAKE_CXXFLAGS"] += project->variables()["QMAKE_CXXFLAGS_RTTI_OFF"];
676     }
677 
678 
679     if ( project->isActiveConfig("moc") )
680 	setMocAware(TRUE);
681     project->variables()["QMAKE_LIBS"] += project->variables()["LIBS"];
682 
683     QStringList &libList = project->variables()["QMAKE_LIBS"];
684     for( QStringList::Iterator stIt = libList.begin(); stIt != libList.end(); ) {
685 	QString s = *stIt;
686 	if( s.startsWith( "-l" ) ) {
687 	    stIt = libList.remove( stIt );
688 	    stIt = libList.insert( stIt, s.mid( 2 ) + ".lib" );
689         } else if( s.startsWith( "-L" ) ) {
690 	    stIt = libList.remove( stIt );
691 	    project->variables()["QMAKE_LIBDIR"].append(QDir::convertSeparators(s.mid( 2 )));
692 	} else {
693 	    stIt++;
694 	}
695     }
696 
697     project->variables()["QMAKE_FILETAGS"] += QStringList::split(' ',
698 	"HEADERS SOURCES DEF_FILE RC_FILE TARGET QMAKE_LIBS DESTDIR DLLDESTDIR INCLUDEPATH");
699     QStringList &l = project->variables()["QMAKE_FILETAGS"];
700     QStringList::Iterator it;
701     for(it = l.begin(); it != l.end(); ++it) {
702 	QStringList &gdmf = project->variables()[(*it)];
703 	for(QStringList::Iterator inner = gdmf.begin(); inner != gdmf.end(); ++inner)
704 	    (*inner) = Option::fixPathToTargetOS((*inner), FALSE);
705     }
706 
707     if ( !project->variables()["DEF_FILE"].isEmpty() )
708 	project->variables()["QMAKE_LFLAGS"].append(QString("/DEF:") + project->first("DEF_FILE"));
709     if(!project->isActiveConfig("incremental"))
710 	project->variables()["QMAKE_LFLAGS"].append(QString("/incremental:no"));
711 
712     if ( !project->variables()["VERSION"].isEmpty() ) {
713 	QString version = project->variables()["VERSION"][0];
714 	int firstDot = version.find( "." );
715 	QString major = version.left( firstDot );
716 	QString minor = version.right( version.length() - firstDot - 1 );
717 	minor.replace( ".", "" );
718 	project->variables()["QMAKE_LFLAGS"].append( "/VERSION:" + major + "." + minor );
719     }
720     if ( !project->variables()["RC_FILE"].isEmpty()) {
721 	if ( !project->variables()["RES_FILE"].isEmpty()) {
722 	    fprintf(stderr, "Both .rc and .res file specified.\n");
723 	    fprintf(stderr, "Please specify one of them, not both.");
724 	    exit(666);
725 	}
726 	project->variables()["RES_FILE"] = project->variables()["RC_FILE"];
727 	project->variables()["RES_FILE"].first().replace(".rc",".res");
728 	project->variables()["POST_TARGETDEPS"] += project->variables()["RES_FILE"];
729 	project->variables()["CLEAN_FILES"] += project->variables()["RES_FILE"];
730     }
731     if ( !project->variables()["RES_FILE"].isEmpty())
732 	project->variables()["QMAKE_LIBS"] += project->variables()["RES_FILE"];
733 
734     // Base class init!
735     MakefileGenerator::init();
736 
737     // Setup PCH variables
738     precompH = project->first("PRECOMPILED_HEADER");
739     usePCH = !precompH.isEmpty() && project->isActiveConfig("precompile_header");
740     if (usePCH) {
741 	// Created files
742 	precompObj = var("OBJECTS_DIR") + project->first("TARGET") + "_pch" + Option::obj_ext;
743 	precompPch = var("OBJECTS_DIR") + project->first("TARGET") + "_pch.pch";
744 	// Add linking of precompObj (required for whole precompiled classes)
745 	project->variables()["OBJECTS"]		  += precompObj;
746 	// Add pch file to cleanup
747 	project->variables()["QMAKE_CLEAN"]	  += precompPch;
748 	// Return to variable pool
749 	project->variables()["PRECOMPILED_OBJECT"] = precompObj;
750 	project->variables()["PRECOMPILED_PCH"]    = precompPch;
751     }
752 
753     if ( !project->variables()["VERSION"].isEmpty()) {
754 	QStringList l = QStringList::split('.', project->first("VERSION"));
755 	project->variables()["VER_MAJ"].append(l[0]);
756 	project->variables()["VER_MIN"].append(l[1]);
757     }
758 
759     QString version = QStringList::split('.', project->first("VERSION")).join("");
760     if(project->isActiveConfig("dll")) {
761 	project->variables()["QMAKE_CLEAN"].append(project->first("DESTDIR") + project->first("TARGET") + version + ".exp");
762     }
763     if(project->isActiveConfig("debug")) {
764 	project->variables()["QMAKE_CLEAN"].append(project->first("DESTDIR") + project->first("TARGET") + version + ".pdb");
765 	project->variables()["QMAKE_CLEAN"].append(project->first("DESTDIR") + project->first("TARGET") + version + ".ilk");
766 	project->variables()["QMAKE_CLEAN"].append("vc*.pdb");
767 	project->variables()["QMAKE_CLEAN"].append("vc*.idb");
768     }
769 
770     QStringList &quc = project->variables()["QMAKE_EXTRA_WIN_COMPILERS"];
771     for(it = quc.begin(); it != quc.end(); ++it) {
772 	QString tmp_out = project->variables()[(*it) + ".output"].first();
773 	if(tmp_out.isEmpty())
774 	    continue;
775 	QStringList &tmp = project->variables()[(*it) + ".input"];
776 	for(QStringList::Iterator it2 = tmp.begin(); it2 != tmp.end(); ++it2) {
777 	    QStringList &inputs = project->variables()[(*it2)];
778 	    for(QStringList::Iterator input = inputs.begin(); input != inputs.end(); ++input) {
779 		QFileInfo fi(Option::fixPathToLocalOS((*input)));
780 		QString in = Option::fixPathToTargetOS((*input), FALSE),
781 		       out = tmp_out;
782 		out.replace("${QMAKE_FILE_BASE}", fi.baseName());
783 		out.replace("${QMAKE_FILE_NAME}", fi.filePath());
784 		if(project->variables()[(*it) + ".CONFIG"].findIndex("no_link") == -1)
785 		    project->variables()["OBJCOMP"] += out;
786 	    }
787 	}
788     }
789 }
790