1
/****************************************************************************
3
** Copyright (C) 1992-2005 Trolltech AS. All rights reserved.
5
** This file is part of the qmake application of the Qt Toolkit.
7
** This file may be distributed under the terms of the Q Public License
8
** as defined by Trolltech AS of Norway and appearing in the file
9
** LICENSE.QPL included in the packaging of this file.
11
** This file may be distributed and/or modified under the terms of the
12
** GNU General Public License version 2 as published by the Free Software
13
** Foundation and appearing in the file LICENSE.GPL included in the
14
** packaging of this file.
16
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
17
** information about Qt Commercial License Agreements.
18
** See http://www.trolltech.com/qpl/ for QPL licensing information.
19
** See http://www.trolltech.com/gpl/ for GPL licensing information.
21
** Contact info@trolltech.com if any conditions of this licensing are
24
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
25
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27
****************************************************************************/
28
#include "metamakefile.h"
34
#define BUILDSMETATYPE 1
35
#define SUBDIRSMETATYPE 2
37
MetaMakefileGenerator::~MetaMakefileGenerator()
42
class BuildsMetaMakefileGenerator : public MetaMakefileGenerator
48
MakefileGenerator *makefile;
50
QList<Build *> makefiles;
52
MakefileGenerator *processBuild(const QString &);
56
BuildsMetaMakefileGenerator(QMakeProject *p) : MetaMakefileGenerator(p), init_flag(false) { }
57
virtual ~BuildsMetaMakefileGenerator() { clearBuilds(); }
60
virtual int type() const { return BUILDSMETATYPE; }
61
virtual bool write(const QString &);
65
BuildsMetaMakefileGenerator::clearBuilds()
67
for(int i = 0; i < makefiles.count(); i++) {
68
Build *build = makefiles[i];
69
delete build->makefile;
76
BuildsMetaMakefileGenerator::init()
82
const QStringList &builds = project->variables()["BUILDS"];
83
bool use_single_build = builds.isEmpty();
84
if(builds.count() > 1 && Option::output.fileName() == "-") {
85
use_single_build = true;
86
warn_msg(WarnLogic, "Cannot direct to stdout when using multiple BUILDS.");
87
} else if(0 && !use_single_build && project->first("TEMPLATE") == "subdirs") {
88
use_single_build = true;
89
warn_msg(WarnLogic, "Cannot specify multiple builds with TEMPLATE subdirs.");
91
if(!use_single_build) {
92
for(int i = 0; i < builds.count(); i++) {
93
QString build = builds[i];
94
MakefileGenerator *makefile = processBuild(build);
97
if(!makefile->supportsMetaBuild()) {
98
warn_msg(WarnLogic, "QMAKESPEC does not support multiple BUILDS.");
100
use_single_build = true;
103
Build *b = new Build;
104
if(builds.count() != 1)
106
b->makefile = makefile;
111
if(use_single_build) {
112
Build *build = new Build;
113
build->makefile = createMakefileGenerator(project);
120
BuildsMetaMakefileGenerator::write(const QString &oldpwd)
123
if(!makefiles.isEmpty() && !makefiles.first()->name.isNull()) {
125
glue->makefile = createMakefileGenerator(project, true);
130
const QString &output_name = Option::output.fileName();
131
for(int i = 0; ret && i < makefiles.count(); i++) {
132
Option::output.setFileName(output_name);
133
Build *build = makefiles[i];
135
bool using_stdout = false;
136
if(build->makefile && (Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE ||
137
Option::qmake_mode == Option::QMAKE_GENERATE_PROJECT)
138
&& (!build->makefile->supportsMergedBuilds()
139
|| (build->makefile->supportsMergedBuilds() && (!glue || build == glue)))) {
141
if(!(Option::output.isOpen())) {
142
if(Option::output.fileName() == "-") {
143
Option::output.setFileName("");
144
Option::output_dir = qmake_getpwd();
145
Option::output.open(stdout, QIODevice::WriteOnly | QIODevice::Text);
148
if(Option::output.fileName().isEmpty() && Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE)
149
Option::output.setFileName(project->first("QMAKE_MAKEFILE"));
150
Option::output_dir = oldpwd;
151
if(!build->makefile->openOutput(Option::output, build->name)) {
152
fprintf(stderr, "Failure to open file: %s\n",
153
Option::output.fileName().isEmpty() ? "(stdout)" :
154
Option::output.fileName().toLatin1().constData());
160
using_stdout = true; //kind of..
163
if(!build->makefile) {
165
} else if(build == glue) {
166
ret = build->makefile->writeProjectMakefile();
168
ret = build->makefile->write();
169
if (glue && glue->makefile->supportsMergedBuilds())
170
ret = glue->makefile->mergeBuildProject(build->makefile);
173
Option::output.close();
175
Option::output.remove();
179
if(Option::debug_level) {
180
QMap<QString, QStringList> &vars = project->variables();
181
for(QMap<QString, QStringList>::Iterator it = vars.begin(); it != vars.end(); ++it) {
182
if(!it.key().startsWith(".") && !it.value().isEmpty())
183
debug_msg(1, "%s === %s", it.key().toLatin1().constData(),
184
it.value().join(" :: ").toLatin1().constData());
192
*BuildsMetaMakefileGenerator::processBuild(const QString &build)
195
debug_msg(1, "Meta Generator: Parsing '%s' for build [%s].",
196
project->projectFile().toLatin1().constData(),build.toLatin1().constData());
198
//initialize the base
199
QMap<QString, QStringList> basevars;
200
if(!project->isEmpty(build + ".CONFIG"))
201
basevars["CONFIG"] += project->values(build + ".CONFIG");
202
basevars["CONFIG"] += build;
203
basevars["CONFIG"] += "build_pass";
204
basevars["BUILD_PASS"] = QStringList(build);
205
QStringList buildname = project->values(build + ".name");
206
basevars["BUILD_NAME"] = (buildname.isEmpty() ? QStringList(build) : buildname);
209
QMakeProject *build_proj = new QMakeProject(project->properities(), basevars);
211
//all the user configs must be set again afterwards (for .pro tests and for .prf tests)
212
const QStringList old_after_user_config = Option::after_user_configs;
213
const QStringList old_user_config = Option::user_configs;
214
Option::after_user_configs += basevars["CONFIG"];
215
Option::user_configs += basevars["CONFIG"];
216
build_proj->read(project->projectFile());
217
Option::after_user_configs = old_after_user_config;
218
Option::user_configs = old_user_config;
221
return createMakefileGenerator(build_proj);
226
class SubdirsMetaMakefileGenerator : public MetaMakefileGenerator
231
Subdir() : makefile(0), indent(0) { }
232
~Subdir() { delete makefile; }
234
QString output_dir, output_file;
235
MetaMakefileGenerator *makefile;
238
QList<Subdir *> subs;
239
MakefileGenerator *processBuild(const QString &);
242
SubdirsMetaMakefileGenerator(QMakeProject *p) : MetaMakefileGenerator(p), init_flag(false) { }
243
virtual ~SubdirsMetaMakefileGenerator();
246
virtual int type() const { return SUBDIRSMETATYPE; }
247
virtual bool write(const QString &);
251
SubdirsMetaMakefileGenerator::init()
257
if(Option::recursive) {
258
const QString old_output_dir = Option::output_dir;
259
const QString oldpwd = qmake_getpwd();
260
const QStringList &subdirs = project->values("SUBDIRS");
261
static int recurseDepth = -1;
263
for(int i = 0; i < subdirs.size(); ++i) {
264
Subdir *sub = new Subdir;
265
sub->indent = recurseDepth;
267
QFileInfo subdir(subdirs.at(i));
269
subdir = QFileInfo(subdirs.at(i) + "/" + subdir.fileName() + Option::pro_ext);
272
QMakeProject *sub_proj = new QMakeProject(project->properities());
273
for (int ind = 0; ind < sub->indent; ++ind)
275
printf("Reading %s\n", subdir.absoluteFilePath().toLatin1().constData());
276
sub->input_dir = subdir.absolutePath();
277
qmake_setpwd(sub->input_dir);
278
sub->output_dir = qmake_getpwd(); //this is not going to work for shadow builds ### --Sam
279
Option::output_dir = sub->output_dir;
280
if(Option::output_dir.at(Option::output_dir.length()-1) != QLatin1Char('/'))
281
Option::output_dir += QLatin1Char('/');
282
sub_proj->read(subdir.fileName());
283
if(!sub_proj->variables()["QMAKE_FAILED_REQUIREMENTS"].isEmpty()) {
284
fprintf(stderr, "Project file(%s) not recursed because all requirements not met:\n\t%s\n",
285
subdir.fileName().toLatin1().constData(),
286
sub_proj->values("QMAKE_FAILED_REQUIREMENTS").join(" ").toLatin1().constData());
291
sub->makefile = MetaMakefileGenerator::createMetaGenerator(sub_proj);
292
if(sub->makefile->type() == SUBDIRSMETATYPE) {
295
const QString &output_name = Option::output.fileName();
296
Option::output.setFileName(sub->output_file);
297
sub->makefile->write(sub->output_dir);
300
Option::output.setFileName(output_name);
302
Option::output_dir = old_output_dir;
303
qmake_setpwd(oldpwd);
307
Option::output_dir = old_output_dir;
308
qmake_setpwd(oldpwd);
311
Subdir *self = new Subdir;
312
self->input_dir = qmake_getpwd();
313
self->output_dir = Option::output_dir;
314
self->output_file = Option::output.fileName();
315
self->makefile = new BuildsMetaMakefileGenerator(project);
316
self->makefile->init();
322
SubdirsMetaMakefileGenerator::write(const QString &passpwd)
325
const QString &oldpwd = qmake_getpwd();
326
const QString &output_dir = Option::output_dir;
327
const QString &output_name = Option::output.fileName();
328
for(int i = 0; ret && i < subs.count(); i++) {
329
const Subdir *sub = subs.at(i);
330
qmake_setpwd(subs.at(i)->input_dir);
331
Option::output_dir = QFileInfo(subs.at(i)->output_dir).absoluteFilePath();
332
if(Option::output_dir.at(Option::output_dir.length()-1) != QLatin1Char('/'))
333
Option::output_dir += QLatin1Char('/');
334
Option::output.setFileName(subs.at(i)->output_file);
335
if(i != subs.count()-1) {
336
for (int ind = 0; ind < sub->indent; ++ind)
338
printf("Writing %s\n", QDir::cleanPath(Option::output_dir+"/"+
339
Option::output.fileName()).toLatin1().constData());
341
QString writepwd = Option::fixPathToLocalOS(qmake_getpwd());
342
if(!writepwd.startsWith(Option::fixPathToLocalOS(passpwd)))
344
if(!(ret = subs.at(i)->makefile->write(writepwd)))
346
qmake_setpwd(oldpwd);
348
//restore because I'm paranoid
349
Option::output.setFileName(output_name);
350
Option::output_dir = output_dir;
354
SubdirsMetaMakefileGenerator::~SubdirsMetaMakefileGenerator()
356
for(int i = 0; i < subs.count(); i++)
362
#include "unixmake.h"
363
#include "mingw_make.h"
364
#include "projectgenerator.h"
365
#ifndef QMAKE_OPENSOURCE_EDITION
366
# include "msvc_nmake.h"
367
# include "borland_bmake.h"
368
# include "metrowerks_xml.h"
369
# include "pbuilder_pbx.h"
370
# include "msvc_dsp.h"
371
# include "msvc_vcproj.h"
375
MetaMakefileGenerator::createMakefileGenerator(QMakeProject *proj, bool noIO)
377
MakefileGenerator *mkfile = NULL;
378
if(Option::qmake_mode == Option::QMAKE_GENERATE_PROJECT) {
379
mkfile = new ProjectGenerator;
380
mkfile->setProjectFile(proj);
385
QString gen = proj->first("MAKEFILE_GENERATOR");
387
fprintf(stderr, "No generator specified in config file: %s\n",
388
proj->projectFile().toLatin1().constData());
389
} else if(gen == "UNIX") {
390
mkfile = new UnixMakefileGenerator;
391
} else if(gen == "MINGW") {
392
mkfile = new MingwMakefileGenerator;
393
#ifndef QMAKE_OPENSOURCE_EDITION
394
} else if(gen == "MSVC") {
395
// Visual Studio =< v6.0
396
if(proj->first("TEMPLATE").indexOf(QRegExp("^vc.*")) != -1)
397
mkfile = new DspMakefileGenerator;
399
mkfile = new NmakeMakefileGenerator;
400
} else if(gen == "MSVC.NET") {
401
// Visual Studio >= v7.0
402
if(proj->first("TEMPLATE").indexOf(QRegExp("^vc.*")) != -1)
403
mkfile = new VcprojGenerator;
405
mkfile = new NmakeMakefileGenerator;
406
} else if(gen == "BMAKE") {
407
mkfile = new BorlandMakefileGenerator;
408
} else if(gen == "METROWERKS") {
409
mkfile = new MetrowerksMakefileGenerator;
410
} else if(gen == "PROJECTBUILDER" || gen == "XCODE") {
411
mkfile = new ProjectBuilderMakefileGenerator;
414
fprintf(stderr, "Unknown generator specified: %s\n", gen.toLatin1().constData());
417
mkfile->setNoIO(noIO);
418
mkfile->setProjectFile(proj);
423
MetaMakefileGenerator *
424
MetaMakefileGenerator::createMetaGenerator(QMakeProject *proj)
426
MetaMakefileGenerator *ret = 0;
427
if((Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE ||
428
Option::qmake_mode == Option::QMAKE_GENERATE_PRL)) {
429
if(proj->first("TEMPLATE").endsWith("subdirs"))
430
ret = new SubdirsMetaMakefileGenerator(proj);
433
ret = new BuildsMetaMakefileGenerator(proj);