Fixing warnings in QScopedPointer test case
[qt-netbsd.git] / qmake / generators / metamakefile.cpp
blob819cdaf34452a97419f0b234decff394f665c9e8
1 /****************************************************************************
2 **
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the qmake application of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
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.
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.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
38 ** $QT_END_LICENSE$
40 ****************************************************************************/
42 #include "metamakefile.h"
43 #include "qregexp.h"
44 #include "qdir.h"
45 #include "qdebug.h"
46 #include "makefile.h"
47 #include "project.h"
48 #include "cachekeys.h"
50 #define BUILDSMETATYPE 1
51 #define SUBDIRSMETATYPE 2
53 QT_BEGIN_NAMESPACE
55 MetaMakefileGenerator::~MetaMakefileGenerator()
57 if(own_project)
58 delete project;
61 class BuildsMetaMakefileGenerator : public MetaMakefileGenerator
63 private:
64 bool init_flag;
65 struct Build {
66 QString name, build;
67 MakefileGenerator *makefile;
69 QList<Build *> makefiles;
70 void clearBuilds();
71 MakefileGenerator *processBuild(const QString &);
73 public:
75 BuildsMetaMakefileGenerator(QMakeProject *p, const QString &n, bool op) : MetaMakefileGenerator(p, n, op), init_flag(false) { }
76 virtual ~BuildsMetaMakefileGenerator() { clearBuilds(); }
78 virtual bool init();
79 virtual int type() const { return BUILDSMETATYPE; }
80 virtual bool write(const QString &);
83 void
84 BuildsMetaMakefileGenerator::clearBuilds()
86 for(int i = 0; i < makefiles.count(); i++) {
87 Build *build = makefiles[i];
88 if(QMakeProject *p = build->makefile->projectFile()) {
89 if(p != project)
90 delete p;
92 delete build->makefile;
93 delete build;
95 makefiles.clear();
98 bool
99 BuildsMetaMakefileGenerator::init()
101 if(init_flag)
102 return false;
103 init_flag = true;
105 const QStringList &builds = project->variables()["BUILDS"];
106 bool use_single_build = builds.isEmpty();
107 if(builds.count() > 1 && Option::output.fileName() == "-") {
108 use_single_build = true;
109 warn_msg(WarnLogic, "Cannot direct to stdout when using multiple BUILDS.");
110 } else if(0 && !use_single_build && project->first("TEMPLATE") == "subdirs") {
111 use_single_build = true;
112 warn_msg(WarnLogic, "Cannot specify multiple builds with TEMPLATE subdirs.");
114 if(!use_single_build) {
115 for(int i = 0; i < builds.count(); i++) {
116 QString build = builds[i];
117 MakefileGenerator *makefile = processBuild(build);
118 if(!makefile)
119 return false;
120 if(!makefile->supportsMetaBuild()) {
121 warn_msg(WarnLogic, "QMAKESPEC does not support multiple BUILDS.");
122 clearBuilds();
123 use_single_build = true;
124 break;
125 } else {
126 Build *b = new Build;
127 b->name = name;
128 if(builds.count() != 1)
129 b->build += build;
130 b->makefile = makefile;
131 makefiles += b;
135 if(use_single_build) {
136 Build *build = new Build;
137 build->name = name;
138 build->makefile = createMakefileGenerator(project, false);
139 if (build->makefile){
140 makefiles += build;
141 }else {
142 delete build;
143 return false;
146 return true;
149 bool
150 BuildsMetaMakefileGenerator::write(const QString &oldpwd)
152 Build *glue = 0;
153 if(!makefiles.isEmpty() && !makefiles.first()->build.isNull()) {
154 glue = new Build;
155 glue->name = name;
156 glue->makefile = createMakefileGenerator(project, true);
157 makefiles += glue;
160 bool ret = true;
161 const QString &output_name = Option::output.fileName();
162 for(int i = 0; ret && i < makefiles.count(); i++) {
163 Option::output.setFileName(output_name);
164 Build *build = makefiles[i];
166 bool using_stdout = false;
167 if(build->makefile && (Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE ||
168 Option::qmake_mode == Option::QMAKE_GENERATE_PROJECT)
169 && (!build->makefile->supportsMergedBuilds()
170 || (build->makefile->supportsMergedBuilds() && (!glue || build == glue)))) {
171 //open output
172 if(!(Option::output.isOpen())) {
173 if(Option::output.fileName() == "-") {
174 Option::output.setFileName("");
175 Option::output_dir = qmake_getpwd();
176 Option::output.open(stdout, QIODevice::WriteOnly | QIODevice::Text);
177 using_stdout = true;
178 } else {
179 if(Option::output.fileName().isEmpty() &&
180 Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE)
181 Option::output.setFileName(project->first("QMAKE_MAKEFILE"));
182 Option::output_dir = oldpwd;
183 QString build_name = build->name;
184 if(!build->build.isEmpty()) {
185 if(!build_name.isEmpty())
186 build_name += ".";
187 build_name += build->build;
189 if(!build->makefile->openOutput(Option::output, build_name)) {
190 fprintf(stderr, "Failure to open file: %s\n",
191 Option::output.fileName().isEmpty() ? "(stdout)" :
192 Option::output.fileName().toLatin1().constData());
193 return false;
197 } else {
198 using_stdout = true; //kind of..
201 if(!build->makefile) {
202 ret = false;
203 } else if(build == glue) {
204 ret = build->makefile->writeProjectMakefile();
205 } else {
206 ret = build->makefile->write();
207 if (glue && glue->makefile->supportsMergedBuilds())
208 ret = glue->makefile->mergeBuildProject(build->makefile);
210 if(!using_stdout) {
211 Option::output.close();
212 if(!ret)
213 Option::output.remove();
216 // debugging
217 if(Option::debug_level) {
218 QMap<QString, QStringList> &vars = project->variables();
219 for(QMap<QString, QStringList>::Iterator it = vars.begin(); it != vars.end(); ++it) {
220 if(!it.key().startsWith(".") && !it.value().isEmpty())
221 debug_msg(1, "%s === %s", it.key().toLatin1().constData(),
222 it.value().join(" :: ").toLatin1().constData());
226 return ret;
229 MakefileGenerator
230 *BuildsMetaMakefileGenerator::processBuild(const QString &build)
232 if(project) {
233 debug_msg(1, "Meta Generator: Parsing '%s' for build [%s].",
234 project->projectFile().toLatin1().constData(),build.toLatin1().constData());
236 //initialize the base
237 QMap<QString, QStringList> basevars;
238 if(!project->isEmpty(build + ".CONFIG"))
239 basevars["CONFIG"] += project->values(build + ".CONFIG");
240 basevars["CONFIG"] += build;
241 basevars["CONFIG"] += "build_pass";
242 basevars["BUILD_PASS"] = QStringList(build);
243 QStringList buildname = project->values(build + ".name");
244 basevars["BUILD_NAME"] = (buildname.isEmpty() ? QStringList(build) : buildname);
246 //create project
247 QMakeProject *build_proj = new QMakeProject(project->properties(), basevars);
249 //all the user configs must be set again afterwards (for .pro tests and for .prf tests)
250 const QStringList old_after_user_config = Option::after_user_configs;
251 const QStringList old_user_config = Option::user_configs;
252 Option::after_user_configs += basevars["CONFIG"];
253 Option::user_configs += basevars["CONFIG"];
254 build_proj->read(project->projectFile());
255 Option::after_user_configs = old_after_user_config;
256 Option::user_configs = old_user_config;
258 //done
259 return createMakefileGenerator(build_proj);
261 return 0;
264 class SubdirsMetaMakefileGenerator : public MetaMakefileGenerator
266 protected:
267 bool init_flag;
268 struct Subdir {
269 Subdir() : makefile(0), indent(0) { }
270 ~Subdir() { delete makefile; }
271 QString input_dir;
272 QString output_dir, output_file;
273 MetaMakefileGenerator *makefile;
274 int indent;
276 QList<Subdir *> subs;
277 MakefileGenerator *processBuild(const QString &);
279 public:
280 SubdirsMetaMakefileGenerator(QMakeProject *p, const QString &n, bool op) : MetaMakefileGenerator(p, n, op), init_flag(false) { }
281 virtual ~SubdirsMetaMakefileGenerator();
283 virtual bool init();
284 virtual int type() const { return SUBDIRSMETATYPE; }
285 virtual bool write(const QString &);
288 bool
289 SubdirsMetaMakefileGenerator::init()
291 if(init_flag)
292 return false;
293 init_flag = true;
294 bool hasError = false;
296 if(Option::recursive) {
297 QString old_output_dir = Option::output_dir;
298 QString old_output = Option::output.fileName();
299 QString oldpwd = qmake_getpwd();
300 QString thispwd = oldpwd;
301 if(!thispwd.endsWith('/'))
302 thispwd += '/';
303 const QStringList &subdirs = project->values("SUBDIRS");
304 static int recurseDepth = -1;
305 ++recurseDepth;
306 for(int i = 0; i < subdirs.size(); ++i) {
307 Subdir *sub = new Subdir;
308 sub->indent = recurseDepth;
310 QFileInfo subdir(subdirs.at(i));
311 if(!project->isEmpty(subdirs.at(i) + ".file"))
312 subdir = project->first(subdirs.at(i) + ".file");
313 else if(!project->isEmpty(subdirs.at(i) + ".subdir"))
314 subdir = project->first(subdirs.at(i) + ".subdir");
315 QString sub_name;
316 if(subdir.isDir())
317 subdir = QFileInfo(subdir.filePath() + "/" + subdir.fileName() + Option::pro_ext);
318 else
319 sub_name = subdir.baseName();
320 if(!subdir.isRelative()) { //we can try to make it relative
321 QString subdir_path = subdir.filePath();
322 if(subdir_path.startsWith(thispwd))
323 subdir = QFileInfo(subdir_path.mid(thispwd.length()));
326 //handle sub project
327 QMakeProject *sub_proj = new QMakeProject(project->properties());
328 for (int ind = 0; ind < sub->indent; ++ind)
329 printf(" ");
330 sub->input_dir = subdir.absolutePath();
331 if(subdir.isRelative() && old_output_dir != oldpwd) {
332 sub->output_dir = old_output_dir + "/" + subdir.path();
333 printf("Reading %s [%s]\n", subdir.absoluteFilePath().toLatin1().constData(), sub->output_dir.toLatin1().constData());
334 } else { //what about shadow builds?
335 sub->output_dir = sub->input_dir;
336 printf("Reading %s\n", subdir.absoluteFilePath().toLatin1().constData());
338 qmake_setpwd(sub->input_dir);
339 Option::output_dir = sub->output_dir;
340 bool tmpError = !sub_proj->read(subdir.fileName());
341 if(!sub_proj->variables()["QMAKE_FAILED_REQUIREMENTS"].isEmpty()) {
342 fprintf(stderr, "Project file(%s) not recursed because all requirements not met:\n\t%s\n",
343 subdir.fileName().toLatin1().constData(),
344 sub_proj->values("QMAKE_FAILED_REQUIREMENTS").join(" ").toLatin1().constData());
345 delete sub;
346 delete sub_proj;
347 Option::output_dir = old_output_dir;
348 qmake_setpwd(oldpwd);
349 continue;
350 } else {
351 hasError |= tmpError;
353 sub->makefile = MetaMakefileGenerator::createMetaGenerator(sub_proj, sub_name);
354 if(0 && sub->makefile->type() == SUBDIRSMETATYPE) {
355 subs.append(sub);
356 } else {
357 const QString output_name = Option::output.fileName();
358 Option::output.setFileName(sub->output_file);
359 hasError |= !sub->makefile->write(sub->output_dir);
360 delete sub;
361 qmakeClearCaches();
362 sub = 0;
363 Option::output.setFileName(output_name);
365 Option::output_dir = old_output_dir;
366 qmake_setpwd(oldpwd);
369 --recurseDepth;
370 Option::output.setFileName(old_output);
371 Option::output_dir = old_output_dir;
372 qmake_setpwd(oldpwd);
375 Subdir *self = new Subdir;
376 self->input_dir = qmake_getpwd();
377 self->output_dir = Option::output_dir;
378 if(!Option::recursive || (!Option::output.fileName().endsWith(Option::dir_sep) && !QFileInfo(Option::output).isDir()))
379 self->output_file = Option::output.fileName();
380 self->makefile = new BuildsMetaMakefileGenerator(project, name, false);
381 self->makefile->init();
382 subs.append(self);
384 return !hasError;
387 bool
388 SubdirsMetaMakefileGenerator::write(const QString &oldpwd)
390 bool ret = true;
391 const QString &pwd = qmake_getpwd();
392 const QString &output_dir = Option::output_dir;
393 const QString &output_name = Option::output.fileName();
394 for(int i = 0; ret && i < subs.count(); i++) {
395 const Subdir *sub = subs.at(i);
396 qmake_setpwd(subs.at(i)->input_dir);
397 Option::output_dir = QFileInfo(subs.at(i)->output_dir).absoluteFilePath();
398 if(Option::output_dir.at(Option::output_dir.length()-1) != QLatin1Char('/'))
399 Option::output_dir += QLatin1Char('/');
400 Option::output.setFileName(subs.at(i)->output_file);
401 if(i != subs.count()-1) {
402 for (int ind = 0; ind < sub->indent; ++ind)
403 printf(" ");
404 printf("Writing %s\n", QDir::cleanPath(Option::output_dir+"/"+
405 Option::output.fileName()).toLatin1().constData());
407 QString writepwd = Option::fixPathToLocalOS(qmake_getpwd());
408 if(!writepwd.startsWith(Option::fixPathToLocalOS(oldpwd)))
409 writepwd = oldpwd;
410 if(!(ret = subs.at(i)->makefile->write(writepwd)))
411 break;
412 //restore because I'm paranoid
413 qmake_setpwd(pwd);
414 Option::output.setFileName(output_name);
415 Option::output_dir = output_dir;
417 return ret;
420 SubdirsMetaMakefileGenerator::~SubdirsMetaMakefileGenerator()
422 for(int i = 0; i < subs.count(); i++)
423 delete subs[i];
424 subs.clear();
427 //Factory things
428 QT_BEGIN_INCLUDE_NAMESPACE
429 #include "unixmake.h"
430 #include "mingw_make.h"
431 #include "projectgenerator.h"
432 #include "pbuilder_pbx.h"
433 #include "msvc_nmake.h"
434 #include "borland_bmake.h"
435 #include "msvc_dsp.h"
436 #include "msvc_vcproj.h"
437 #include "symmake_abld.h"
438 #include "symmake_sbsv2.h"
439 QT_END_INCLUDE_NAMESPACE
441 MakefileGenerator *
442 MetaMakefileGenerator::createMakefileGenerator(QMakeProject *proj, bool noIO)
444 MakefileGenerator *mkfile = NULL;
445 if(Option::qmake_mode == Option::QMAKE_GENERATE_PROJECT) {
446 mkfile = new ProjectGenerator;
447 mkfile->setProjectFile(proj);
448 return mkfile;
451 QString gen = proj->first("MAKEFILE_GENERATOR");
452 if(gen.isEmpty()) {
453 fprintf(stderr, "MAKEFILE_GENERATOR variable not set as a result of parsing : %s. Possibly qmake was not able to find files included using \"include(..)\" - enable qmake debugging to investigate more.\n",
454 proj->projectFile().toLatin1().constData());
455 } else if(gen == "UNIX") {
456 mkfile = new UnixMakefileGenerator;
457 } else if(gen == "MINGW") {
458 mkfile = new MingwMakefileGenerator;
459 } else if(gen == "PROJECTBUILDER" || gen == "XCODE") {
460 mkfile = new ProjectBuilderMakefileGenerator;
461 } else if(gen == "MSVC") {
462 // Visual Studio =< v6.0
463 if(proj->first("TEMPLATE").indexOf(QRegExp("^vc.*")) != -1)
464 mkfile = new DspMakefileGenerator;
465 else
466 mkfile = new NmakeMakefileGenerator;
467 } else if(gen == "MSVC.NET") {
468 // Visual Studio >= v7.0
469 if(proj->first("TEMPLATE").indexOf(QRegExp("^vc.*")) != -1 || proj->first("TEMPLATE").indexOf(QRegExp("^ce.*")) != -1)
470 mkfile = new VcprojGenerator;
471 else
472 mkfile = new NmakeMakefileGenerator;
473 } else if(gen == "BMAKE") {
474 mkfile = new BorlandMakefileGenerator;
475 } else if(gen == "SYMBIAN_ABLD") {
476 mkfile = new SymbianAbldMakefileGenerator;
477 } else if(gen == "SYMBIAN_SBSV2") {
478 mkfile = new SymbianSbsv2MakefileGenerator;
479 } else {
480 fprintf(stderr, "Unknown generator specified: %s\n", gen.toLatin1().constData());
482 if (mkfile) {
483 mkfile->setNoIO(noIO);
484 mkfile->setProjectFile(proj);
486 return mkfile;
489 MetaMakefileGenerator *
490 MetaMakefileGenerator::createMetaGenerator(QMakeProject *proj, const QString &name, bool op, bool *success)
492 MetaMakefileGenerator *ret = 0;
493 if ((Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE ||
494 Option::qmake_mode == Option::QMAKE_GENERATE_PRL)) {
495 if (proj->first("TEMPLATE").endsWith("subdirs"))
496 ret = new SubdirsMetaMakefileGenerator(proj, name, op);
498 if (!ret)
499 ret = new BuildsMetaMakefileGenerator(proj, name, op);
500 bool res = ret->init();
501 if (success)
502 *success = res;
503 return ret;
506 QT_END_NAMESPACE