~oif-team/ubuntu/natty/qt4-x11/xi2.1

« back to all changes in this revision

Viewing changes to qmake/generators/metamakefile.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Adam Conrad
  • Date: 2005-08-24 04:09:09 UTC
  • Revision ID: james.westby@ubuntu.com-20050824040909-xmxe9jfr4a0w5671
Tags: upstream-4.0.0
ImportĀ upstreamĀ versionĀ 4.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/****************************************************************************
 
2
**
 
3
** Copyright (C) 1992-2005 Trolltech AS. All rights reserved.
 
4
**
 
5
** This file is part of the qmake application of the Qt Toolkit.
 
6
**
 
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.
 
10
**
 
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.
 
15
**
 
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.
 
20
**
 
21
** Contact info@trolltech.com if any conditions of this licensing are
 
22
** not clear to you.
 
23
**
 
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.
 
26
**
 
27
****************************************************************************/
 
28
#include "metamakefile.h"
 
29
#include "qregexp.h"
 
30
#include "qdir.h"
 
31
#include "makefile.h"
 
32
#include "project.h"
 
33
 
 
34
#define BUILDSMETATYPE 1
 
35
#define SUBDIRSMETATYPE 2
 
36
 
 
37
MetaMakefileGenerator::~MetaMakefileGenerator()
 
38
{
 
39
 
 
40
}
 
41
 
 
42
class BuildsMetaMakefileGenerator : public MetaMakefileGenerator
 
43
{
 
44
    bool init_flag;
 
45
private:
 
46
    struct Build {
 
47
        QString name;
 
48
        MakefileGenerator *makefile;
 
49
    };
 
50
    QList<Build *> makefiles;
 
51
    void clearBuilds();
 
52
    MakefileGenerator *processBuild(const QString &);
 
53
 
 
54
public:
 
55
 
 
56
    BuildsMetaMakefileGenerator(QMakeProject *p) : MetaMakefileGenerator(p), init_flag(false) { }
 
57
    virtual ~BuildsMetaMakefileGenerator() { clearBuilds(); }
 
58
 
 
59
    virtual bool init();
 
60
    virtual int type() const { return BUILDSMETATYPE; }
 
61
    virtual bool write(const QString &);
 
62
};
 
63
 
 
64
void
 
65
BuildsMetaMakefileGenerator::clearBuilds()
 
66
{
 
67
    for(int i = 0; i < makefiles.count(); i++) {
 
68
        Build *build = makefiles[i];
 
69
        delete build->makefile;
 
70
        delete build;
 
71
    }
 
72
    makefiles.clear();
 
73
}
 
74
 
 
75
bool
 
76
BuildsMetaMakefileGenerator::init()
 
77
{
 
78
    if(init_flag)
 
79
        return false;
 
80
    init_flag = true;
 
81
 
 
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.");
 
90
    }
 
91
    if(!use_single_build) {
 
92
        for(int i = 0; i < builds.count(); i++) {
 
93
            QString build = builds[i];
 
94
            MakefileGenerator *makefile = processBuild(build);
 
95
            if(!makefile)
 
96
                return false;
 
97
            if(!makefile->supportsMetaBuild()) {
 
98
                warn_msg(WarnLogic, "QMAKESPEC does not support multiple BUILDS.");
 
99
                clearBuilds();
 
100
                use_single_build = true;
 
101
                break;
 
102
            } else {
 
103
                Build *b = new Build;
 
104
                if(builds.count() != 1)
 
105
                    b->name = build;
 
106
                b->makefile = makefile;
 
107
                makefiles += b;
 
108
            }
 
109
        }
 
110
    }
 
111
    if(use_single_build) {
 
112
        Build *build = new Build;
 
113
        build->makefile = createMakefileGenerator(project);
 
114
        makefiles += build;
 
115
    }
 
116
    return true;
 
117
}
 
118
 
 
119
bool
 
120
BuildsMetaMakefileGenerator::write(const QString &oldpwd)
 
121
{
 
122
    Build *glue = 0;
 
123
    if(!makefiles.isEmpty() && !makefiles.first()->name.isNull()) {
 
124
        glue = new Build;
 
125
        glue->makefile = createMakefileGenerator(project, true);
 
126
        makefiles += glue;
 
127
    }
 
128
 
 
129
    bool ret = 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];
 
134
 
 
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)))) {
 
140
            //open output
 
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);
 
146
                    using_stdout = true;
 
147
                } else {
 
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());
 
155
                        return false;
 
156
                    }
 
157
                }
 
158
            }
 
159
        } else {
 
160
           using_stdout = true; //kind of..
 
161
        }
 
162
 
 
163
        if(!build->makefile) {
 
164
            ret = false;
 
165
        } else if(build == glue) {
 
166
            ret = build->makefile->writeProjectMakefile();
 
167
        } else {
 
168
            ret = build->makefile->write();
 
169
            if (glue && glue->makefile->supportsMergedBuilds())
 
170
                ret = glue->makefile->mergeBuildProject(build->makefile);
 
171
        }
 
172
        if(!using_stdout) {
 
173
            Option::output.close();
 
174
            if(!ret)
 
175
                Option::output.remove();
 
176
        }
 
177
 
 
178
        // debugging
 
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());
 
185
            }
 
186
        }
 
187
    }
 
188
    return ret;
 
189
}
 
190
 
 
191
MakefileGenerator
 
192
*BuildsMetaMakefileGenerator::processBuild(const QString &build)
 
193
{
 
194
    if(project) {
 
195
        debug_msg(1, "Meta Generator: Parsing '%s' for build [%s].",
 
196
                  project->projectFile().toLatin1().constData(),build.toLatin1().constData());
 
197
 
 
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);
 
207
 
 
208
        //create project
 
209
        QMakeProject *build_proj = new QMakeProject(project->properities(), basevars);
 
210
 
 
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;
 
219
 
 
220
        //done
 
221
        return createMakefileGenerator(build_proj);
 
222
    }
 
223
    return 0;
 
224
}
 
225
 
 
226
class SubdirsMetaMakefileGenerator : public MetaMakefileGenerator
 
227
{
 
228
    bool init_flag;
 
229
private:
 
230
    struct Subdir {
 
231
        Subdir() : makefile(0), indent(0) { }
 
232
        ~Subdir() { delete makefile; }
 
233
        QString input_dir;
 
234
        QString output_dir, output_file;
 
235
        MetaMakefileGenerator *makefile;
 
236
        int indent;
 
237
    };
 
238
    QList<Subdir *> subs;
 
239
    MakefileGenerator *processBuild(const QString &);
 
240
 
 
241
public:
 
242
    SubdirsMetaMakefileGenerator(QMakeProject *p) : MetaMakefileGenerator(p), init_flag(false) { }
 
243
    virtual ~SubdirsMetaMakefileGenerator();
 
244
 
 
245
    virtual bool init();
 
246
    virtual int type() const { return SUBDIRSMETATYPE; }
 
247
    virtual bool write(const QString &);
 
248
};
 
249
 
 
250
bool
 
251
SubdirsMetaMakefileGenerator::init()
 
252
{
 
253
    if(init_flag)
 
254
        return false;
 
255
    init_flag = true;
 
256
 
 
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;
 
262
        ++recurseDepth;
 
263
        for(int i = 0; i < subdirs.size(); ++i) {
 
264
            Subdir *sub = new Subdir;
 
265
            sub->indent = recurseDepth;
 
266
 
 
267
            QFileInfo subdir(subdirs.at(i));
 
268
            if(subdir.isDir())
 
269
                subdir = QFileInfo(subdirs.at(i) + "/" + subdir.fileName() + Option::pro_ext);
 
270
 
 
271
            //handle sub project
 
272
            QMakeProject *sub_proj = new QMakeProject(project->properities());
 
273
            for (int ind = 0; ind < sub->indent; ++ind)
 
274
                printf(" ");
 
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());
 
287
                delete sub;
 
288
                delete sub_proj;
 
289
                continue;
 
290
            }
 
291
            sub->makefile = MetaMakefileGenerator::createMetaGenerator(sub_proj);
 
292
            if(sub->makefile->type() == SUBDIRSMETATYPE) {
 
293
                subs.append(sub);
 
294
            } else {
 
295
                const QString &output_name = Option::output.fileName();
 
296
                Option::output.setFileName(sub->output_file);
 
297
                sub->makefile->write(sub->output_dir);
 
298
                delete sub;
 
299
                sub = 0;
 
300
                Option::output.setFileName(output_name);
 
301
            }
 
302
            Option::output_dir = old_output_dir;
 
303
            qmake_setpwd(oldpwd);
 
304
 
 
305
        }
 
306
        --recurseDepth;
 
307
        Option::output_dir = old_output_dir;
 
308
        qmake_setpwd(oldpwd);
 
309
    }
 
310
 
 
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();
 
317
    subs.append(self);
 
318
    return true;
 
319
}
 
320
 
 
321
bool
 
322
SubdirsMetaMakefileGenerator::write(const QString &passpwd)
 
323
{
 
324
    bool ret = true;
 
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)
 
337
                printf(" ");
 
338
            printf("Writing %s\n", QDir::cleanPath(Option::output_dir+"/"+
 
339
                                                   Option::output.fileName()).toLatin1().constData());
 
340
        }
 
341
        QString writepwd = Option::fixPathToLocalOS(qmake_getpwd());
 
342
        if(!writepwd.startsWith(Option::fixPathToLocalOS(passpwd)))
 
343
            writepwd = passpwd;
 
344
        if(!(ret = subs.at(i)->makefile->write(writepwd)))
 
345
            break;
 
346
        qmake_setpwd(oldpwd);
 
347
    }
 
348
    //restore because I'm paranoid
 
349
    Option::output.setFileName(output_name);
 
350
    Option::output_dir = output_dir;
 
351
    return ret;
 
352
}
 
353
 
 
354
SubdirsMetaMakefileGenerator::~SubdirsMetaMakefileGenerator()
 
355
{
 
356
    for(int i = 0; i < subs.count(); i++)
 
357
        delete subs[i];
 
358
    subs.clear();
 
359
}
 
360
 
 
361
//Factory things
 
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"
 
372
#endif
 
373
 
 
374
MakefileGenerator *
 
375
MetaMakefileGenerator::createMakefileGenerator(QMakeProject *proj, bool noIO)
 
376
{
 
377
    MakefileGenerator *mkfile = NULL;
 
378
    if(Option::qmake_mode == Option::QMAKE_GENERATE_PROJECT) {
 
379
        mkfile = new ProjectGenerator;
 
380
        mkfile->setProjectFile(proj);
 
381
        return mkfile;
 
382
    }
 
383
 
 
384
 
 
385
    QString gen = proj->first("MAKEFILE_GENERATOR");
 
386
    if(gen.isEmpty()) {
 
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;
 
398
        else
 
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;
 
404
        else
 
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;
 
412
#endif
 
413
    } else {
 
414
        fprintf(stderr, "Unknown generator specified: %s\n", gen.toLatin1().constData());
 
415
    }
 
416
    if (mkfile) {
 
417
        mkfile->setNoIO(noIO);
 
418
        mkfile->setProjectFile(proj);
 
419
    }
 
420
    return mkfile;
 
421
}
 
422
 
 
423
MetaMakefileGenerator *
 
424
MetaMakefileGenerator::createMetaGenerator(QMakeProject *proj)
 
425
{
 
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);
 
431
    }
 
432
    if(!ret)
 
433
        ret = new BuildsMetaMakefileGenerator(proj);
 
434
    ret->init();
 
435
    return ret;
 
436
}
 
437