qmake/generators/metamakefile.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/qmake/generators/metamakefile.cpp	Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,778 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the qmake application of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "metamakefile.h"
+#include "qregexp.h"
+#include "qdir.h"
+#include "qdebug.h"
+#include "makefile.h"
+#include "project.h"
+#include "cachekeys.h"
+
+#define BUILDSMETATYPE 1
+#define SUBDIRSMETATYPE 2
+
+QT_BEGIN_NAMESPACE
+
+MetaMakefileGenerator::~MetaMakefileGenerator()
+{
+    if(own_project)
+        delete project;
+}
+
+class BuildsMetaMakefileGenerator : public MetaMakefileGenerator
+{
+private:
+    bool init_flag;
+    struct Build {
+        QString name, build;
+        MakefileGenerator *makefile;
+    };
+    QList<Build *> makefiles;
+    void clearBuilds();
+    MakefileGenerator *processBuild(const QString &);
+
+public:
+
+    BuildsMetaMakefileGenerator(QMakeProject *p, const QString &n, bool op) : MetaMakefileGenerator(p, n, op), init_flag(false) { }
+    virtual ~BuildsMetaMakefileGenerator() { clearBuilds(); }
+
+    virtual bool init();
+    virtual int type() const { return BUILDSMETATYPE; }
+    virtual bool write(const QString &);
+};
+
+void
+BuildsMetaMakefileGenerator::clearBuilds()
+{
+    for(int i = 0; i < makefiles.count(); i++) {
+        Build *build = makefiles[i];
+        if(QMakeProject *p = build->makefile->projectFile()) {
+            if(p != project)
+                delete p;
+        }
+        delete build->makefile;
+        delete build;
+    }
+    makefiles.clear();
+}
+
+bool
+BuildsMetaMakefileGenerator::init()
+{
+    if(init_flag)
+        return false;
+    init_flag = true;
+
+    const QStringList &builds = project->variables()["BUILDS"];
+    bool use_single_build = builds.isEmpty();
+    if(builds.count() > 1 && Option::output.fileName() == "-") {
+        use_single_build = true;
+        warn_msg(WarnLogic, "Cannot direct to stdout when using multiple BUILDS.");
+    } else if(0 && !use_single_build && project->first("TEMPLATE") == "subdirs") {
+        use_single_build = true;
+        warn_msg(WarnLogic, "Cannot specify multiple builds with TEMPLATE subdirs.");
+    }
+    if(!use_single_build) {
+        for(int i = 0; i < builds.count(); i++) {
+            QString build = builds[i];
+            MakefileGenerator *makefile = processBuild(build);
+            if(!makefile)
+                return false;
+            if(!makefile->supportsMetaBuild()) {
+                warn_msg(WarnLogic, "QMAKESPEC does not support multiple BUILDS.");
+                clearBuilds();
+                use_single_build = true;
+                break;
+            } else {
+                Build *b = new Build;
+                b->name = name;
+                if(builds.count() != 1)
+                    b->build += build;
+                b->makefile = makefile;
+                makefiles += b;
+            }
+        }
+    }
+    if(use_single_build) {
+        Build *build = new Build;
+        build->name = name;
+        build->makefile = createMakefileGenerator(project, false);
+	if (build->makefile){
+            makefiles += build;
+	}else {
+	    delete build;
+	    return false;
+	}
+    }
+    return true;
+}
+
+bool
+BuildsMetaMakefileGenerator::write(const QString &oldpwd)
+{
+    Build *glue = 0;
+    if(!makefiles.isEmpty() && !makefiles.first()->build.isNull()) {
+        glue = new Build;
+        glue->name = name;
+        glue->makefile = createMakefileGenerator(project, true);
+        makefiles += glue;
+    }
+
+    bool ret = true;
+    const QString &output_name = Option::output.fileName();
+    for(int i = 0; ret && i < makefiles.count(); i++) {
+        Option::output.setFileName(output_name);
+        Build *build = makefiles[i];
+
+        bool using_stdout = false;
+        if(build->makefile && (Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE ||
+                               Option::qmake_mode == Option::QMAKE_GENERATE_PROJECT)
+           && (!build->makefile->supportsMergedBuilds()
+            || (build->makefile->supportsMergedBuilds() && (!glue || build == glue)))) {
+            //open output
+            if(!(Option::output.isOpen())) {
+                if(Option::output.fileName() == "-") {
+                    Option::output.setFileName("");
+                    Option::output_dir = qmake_getpwd();
+                    Option::output.open(stdout, QIODevice::WriteOnly | QIODevice::Text);
+                    using_stdout = true;
+                } else {
+                    if(Option::output.fileName().isEmpty() &&
+		       Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE)
+                        Option::output.setFileName(project->first("QMAKE_MAKEFILE"));
+                    Option::output_dir = oldpwd;
+                    QString build_name = build->name;
+                    if(!build->build.isEmpty()) {
+                        if(!build_name.isEmpty())
+                            build_name += ".";
+                        build_name += build->build;
+                    }
+                    if(!build->makefile->openOutput(Option::output, build_name)) {
+                        fprintf(stderr, "Failure to open file: %s\n",
+                                Option::output.fileName().isEmpty() ? "(stdout)" :
+                                Option::output.fileName().toLatin1().constData());
+                        return false;
+                    }
+                }
+            }
+        } else {
+           using_stdout = true; //kind of..
+        }
+
+        if(!build->makefile) {
+            ret = false;
+        } else if(build == glue) {
+            ret = build->makefile->writeProjectMakefile();
+        } else {
+            ret = build->makefile->write();
+            if (glue && glue->makefile->supportsMergedBuilds())
+                ret = glue->makefile->mergeBuildProject(build->makefile);
+        }
+        if(!using_stdout) {
+            Option::output.close();
+            if(!ret)
+                Option::output.remove();
+        }
+
+        // debugging
+        if(Option::debug_level) {
+            QMap<QString, QStringList> &vars = project->variables();
+            for(QMap<QString, QStringList>::Iterator it = vars.begin(); it != vars.end(); ++it) {
+                if(!it.key().startsWith(".") && !it.value().isEmpty())
+                    debug_msg(1, "%s === %s", it.key().toLatin1().constData(),
+                              it.value().join(" :: ").toLatin1().constData());
+            }
+        }
+    }
+    return ret;
+}
+
+MakefileGenerator
+*BuildsMetaMakefileGenerator::processBuild(const QString &build)
+{
+    if(project) {
+        debug_msg(1, "Meta Generator: Parsing '%s' for build [%s].",
+                  project->projectFile().toLatin1().constData(),build.toLatin1().constData());
+
+        //initialize the base
+        QMap<QString, QStringList> basevars;
+        if(!project->isEmpty(build + ".CONFIG"))
+            basevars["CONFIG"] += project->values(build + ".CONFIG");
+        basevars["CONFIG"] += build;
+        basevars["CONFIG"] += "build_pass";
+        basevars["BUILD_PASS"] = QStringList(build);
+        QStringList buildname = project->values(build + ".name");
+        basevars["BUILD_NAME"] = (buildname.isEmpty() ? QStringList(build) : buildname);
+
+        //create project
+        QMakeProject *build_proj = new QMakeProject(project->properties(), basevars);
+
+        //all the user configs must be set again afterwards (for .pro tests and for .prf tests)
+        const QStringList old_after_user_config = Option::after_user_configs;
+        const QStringList old_user_config = Option::user_configs;
+        Option::after_user_configs += basevars["CONFIG"];
+        Option::user_configs += basevars["CONFIG"];
+        build_proj->read(project->projectFile());
+        Option::after_user_configs = old_after_user_config;
+        Option::user_configs = old_user_config;
+
+        //done
+        return createMakefileGenerator(build_proj);
+    }
+    return 0;
+}
+
+class SubdirsMetaMakefileGenerator : public MetaMakefileGenerator
+{
+protected:
+    bool init_flag;
+    struct Subdir {
+        Subdir() : makefile(0), indent(0) { }
+        ~Subdir() { delete makefile; }
+        QString input_dir;
+        QString output_dir, output_file;
+        MetaMakefileGenerator *makefile;
+        int indent;
+    };
+    QList<Subdir *> subs;
+    MakefileGenerator *processBuild(const QString &);
+
+public:
+    SubdirsMetaMakefileGenerator(QMakeProject *p, const QString &n, bool op) : MetaMakefileGenerator(p, n, op), init_flag(false) { }
+    virtual ~SubdirsMetaMakefileGenerator();
+
+    virtual bool init();
+    virtual int type() const { return SUBDIRSMETATYPE; }
+    virtual bool write(const QString &);
+};
+
+bool
+SubdirsMetaMakefileGenerator::init()
+{
+    if(init_flag)
+        return false;
+    init_flag = true;
+    bool hasError = false;
+
+    if(Option::recursive) {
+        QString old_output_dir = Option::output_dir;
+	QString old_output = Option::output.fileName();
+        QString oldpwd = qmake_getpwd();
+        QString thispwd = oldpwd;
+        if(!thispwd.endsWith('/'))
+           thispwd += '/';
+        const QStringList &subdirs = project->values("SUBDIRS");
+        static int recurseDepth = -1;
+        ++recurseDepth;
+        for(int i = 0; i < subdirs.size(); ++i) {
+            Subdir *sub = new Subdir;
+            sub->indent = recurseDepth;
+
+            QFileInfo subdir(subdirs.at(i));
+            if(!project->isEmpty(subdirs.at(i) + ".file"))
+                subdir = project->first(subdirs.at(i) + ".file");
+            else if(!project->isEmpty(subdirs.at(i) + ".subdir"))
+                subdir = project->first(subdirs.at(i) + ".subdir");
+            QString sub_name;
+            if(subdir.isDir())
+                subdir = QFileInfo(subdir.filePath() + "/" + subdir.fileName() + Option::pro_ext);
+            else
+                sub_name = subdir.baseName();
+            if(!subdir.isRelative()) { //we can try to make it relative
+                QString subdir_path = subdir.filePath();
+                if(subdir_path.startsWith(thispwd))
+                    subdir = QFileInfo(subdir_path.mid(thispwd.length()));
+            }
+
+            //handle sub project
+            QMakeProject *sub_proj = new QMakeProject(project->properties());
+            if (!Option::mkfile::listgen) {
+                for (int ind = 0; ind < sub->indent; ++ind)
+                    printf(" ");
+            }
+
+            sub->input_dir = subdir.absolutePath();
+            if(subdir.isRelative() && old_output_dir != oldpwd) {
+                sub->output_dir = old_output_dir + "/" + subdir.path();
+                printf("Reading %s [%s]\n", subdir.absoluteFilePath().toLatin1().constData(), sub->output_dir.toLatin1().constData());
+            } else { //what about shadow builds?
+                sub->output_dir = sub->input_dir;
+                printf("Reading %s\n", subdir.absoluteFilePath().toLatin1().constData());
+            }
+            qmake_setpwd(sub->input_dir);
+            Option::output_dir = sub->output_dir;
+            bool tmpError = !sub_proj->read(subdir.fileName());
+            if(!sub_proj->variables()["QMAKE_FAILED_REQUIREMENTS"].isEmpty()) {
+                fprintf(stderr, "Project file(%s) not recursed because all requirements not met:\n\t%s\n",
+                        subdir.fileName().toLatin1().constData(),
+                        sub_proj->values("QMAKE_FAILED_REQUIREMENTS").join(" ").toLatin1().constData());
+                delete sub;
+                delete sub_proj;
+                Option::output_dir = old_output_dir;
+                qmake_setpwd(oldpwd);
+                continue;
+            } else {
+                hasError |= tmpError;
+            }
+            sub->makefile = MetaMakefileGenerator::createMetaGenerator(sub_proj, sub_name);
+            if(0 && sub->makefile->type() == SUBDIRSMETATYPE) {
+                subs.append(sub);
+            } else {
+                const QString output_name = Option::output.fileName();
+                Option::output.setFileName(sub->output_file);
+                hasError |= !sub->makefile->write(sub->output_dir);
+                delete sub;
+                qmakeClearCaches();
+                sub = 0;
+                Option::output.setFileName(output_name);
+            }
+            Option::output_dir = old_output_dir;
+            qmake_setpwd(oldpwd);
+
+        }
+        --recurseDepth;
+        Option::output.setFileName(old_output);
+        Option::output_dir = old_output_dir;
+        qmake_setpwd(oldpwd);
+    }
+
+    Subdir *self = new Subdir;
+    self->input_dir = qmake_getpwd();
+    self->output_dir = Option::output_dir;
+    if(!Option::recursive || (!Option::output.fileName().endsWith(Option::dir_sep) && !QFileInfo(Option::output).isDir()))
+	self->output_file = Option::output.fileName();
+    self->makefile = new BuildsMetaMakefileGenerator(project, name, false);
+    self->makefile->init();
+    subs.append(self);
+
+    return !hasError;
+}
+
+bool
+SubdirsMetaMakefileGenerator::write(const QString &oldpwd)
+{
+    bool ret = true;
+    const QString &pwd = qmake_getpwd();
+    const QString &output_dir = Option::output_dir;
+    const QString &output_name = Option::output.fileName();
+    for(int i = 0; ret && i < subs.count(); i++) {
+        const Subdir *sub = subs.at(i);
+        qmake_setpwd(subs.at(i)->input_dir);
+        Option::output_dir = QFileInfo(subs.at(i)->output_dir).absoluteFilePath();
+        if(Option::output_dir.at(Option::output_dir.length()-1) != QLatin1Char('/'))
+            Option::output_dir += QLatin1Char('/');
+        Option::output.setFileName(subs.at(i)->output_file);
+        if(i != subs.count()-1) {
+            if (!Option::mkfile::listgen) {
+                for (int ind = 0; ind < sub->indent; ++ind)
+                    printf(" ");
+            }
+            printf("Writing %s\n", QDir::cleanPath(Option::output_dir+"/"+
+                                                   Option::output.fileName()).toLatin1().constData());
+        }
+        QString writepwd = Option::fixPathToLocalOS(qmake_getpwd());
+        if(!writepwd.startsWith(Option::fixPathToLocalOS(oldpwd)))
+            writepwd = oldpwd;
+        if(!(ret = subs.at(i)->makefile->write(writepwd)))
+            break;
+	//restore because I'm paranoid
+        qmake_setpwd(pwd);
+	Option::output.setFileName(output_name);
+	Option::output_dir = output_dir;
+    }
+    return ret;
+}
+
+SubdirsMetaMakefileGenerator::~SubdirsMetaMakefileGenerator()
+{
+    for(int i = 0; i < subs.count(); i++)
+        delete subs[i];
+    subs.clear();
+}
+
+class SymbianSubdirsMetaMakefileGenerator : public SubdirsMetaMakefileGenerator
+{
+public:
+    SymbianSubdirsMetaMakefileGenerator(QMakeProject *p, const QString &n, bool op) : SubdirsMetaMakefileGenerator(p, n, op) { }
+    virtual ~SymbianSubdirsMetaMakefileGenerator();
+
+    virtual bool init();
+    virtual bool write(const QString &);
+
+protected:
+
+    static QMap<QString, QString> mmpPaths;
+
+    static QMultiMap<QString, QString> mmpDependency;
+
+    static QStringList getDependencyList(QString mmpFilename, int recursionDepth);
+
+    static QStringList calculateRelativePaths(QString mmpParent, QStringList mmpChildren);
+
+private:
+    QString cleanFromSpecialCharacters(QString& str);
+};
+
+QMap<QString, QString> SymbianSubdirsMetaMakefileGenerator::mmpPaths;
+
+QMultiMap<QString, QString> SymbianSubdirsMetaMakefileGenerator::mmpDependency;
+
+QStringList SymbianSubdirsMetaMakefileGenerator::getDependencyList(QString mmpFilename, int recursionDepth)
+{
+    QStringList list;
+
+    QList<QString> values = mmpDependency.values(mmpFilename);
+    if (recursionDepth < 0) {
+        // special case; just first dependency level
+        list = values;
+        return list;
+    }
+    if (values.size() == 0) {
+        //reached recursion END condition
+        if (recursionDepth == 0) {
+            --recursionDepth;
+            return list; // empty list // no dependencies / return
+        } else {
+            list.append(mmpFilename);
+            recursionDepth--;
+            return list; // leaf // return
+        }
+    } else {
+        recursionDepth++;
+        for (int i = 0; i < values.size(); ++i) {
+            QString current = values.at(i);
+            QStringList tailList = getDependencyList(current, recursionDepth);
+            for (int j = 0; j < tailList.size(); ++j) {
+                QString path = tailList.at(j);
+                list.append(path);
+            }
+        }
+
+        if (recursionDepth > 0) {
+            //for mmp somewhere in middle
+            list.append(mmpFilename);
+        }
+        recursionDepth--;
+        return list;
+    }
+}
+
+SymbianSubdirsMetaMakefileGenerator::~SymbianSubdirsMetaMakefileGenerator() { }
+
+bool SymbianSubdirsMetaMakefileGenerator::write(const QString &oldpwd)
+{
+    return SubdirsMetaMakefileGenerator::write(oldpwd);
+}
+
+QString SymbianSubdirsMetaMakefileGenerator::cleanFromSpecialCharacters(QString& str)
+{
+    QString tmp = str;
+
+    tmp.replace(QString("/"), QString("_"));
+    tmp.replace(QString("\\"), QString("_"));
+    tmp.replace(QString("-"), QString("_"));
+    tmp.replace(QString(":"), QString("_"));
+    tmp.replace(QString("."), QString("_"));
+
+    return tmp;
+}
+
+bool SymbianSubdirsMetaMakefileGenerator::init()
+{
+    if (init_flag)
+        return false;
+
+    init_flag = true;
+
+    // If we are here then we have template == subdirs
+
+    Option::recursive = true;
+
+    if (Option::recursive) {
+        QString old_output_dir = QDir::cleanPath(Option::output_dir);
+        if (!old_output_dir.endsWith('/'))
+            old_output_dir += '/';
+        QString old_output = Option::output.fileName();
+        QString oldpwd = QDir::cleanPath(qmake_getpwd());
+
+        if (!oldpwd.endsWith('/'))
+            oldpwd += '/';
+
+        // find the parent mmp filename
+        int end = oldpwd.size() - 1;
+        int start = oldpwd.lastIndexOf("/", end - 2);
+        QString parentMmpFilename = oldpwd.mid(start + 1, end - start - 1);
+        parentMmpFilename.prepend(oldpwd);
+        parentMmpFilename = parentMmpFilename.append(Option::mmp_ext);
+
+
+        const QStringList &subdirs = project->values("SUBDIRS");
+        static int recurseDepth = -1;
+        ++recurseDepth;
+        for (int i = 0; i < subdirs.size(); ++i) {
+            Subdir *sub = new Subdir;
+            sub->indent = recurseDepth;
+
+            QFileInfo subdir(subdirs.at(i));
+            // childMmpFielname should be derived from subdirName
+            QString subdirName = subdirs.at(i);
+            if (!project->isEmpty(subdirs.at(i) + ".file"))
+                subdir = project->first(subdirs.at(i) + ".file");
+            else if (!project->isEmpty(subdirs.at(i) + ".subdir"))
+                subdir = project->first(subdirs.at(i) + ".subdir");
+            QString sub_name;
+
+            QString childMmpFilename;
+
+            if (subdir.isDir()) {
+                subdir = QFileInfo(subdir.filePath() + "/" + subdir.fileName() + Option::pro_ext);
+                childMmpFilename = subdir.fileName();
+                childMmpFilename = subdir.absoluteFilePath();
+                childMmpFilename.replace(Option::pro_ext, QString(""));
+                childMmpFilename.append(Option::mmp_ext);
+            } else {
+                childMmpFilename = subdir.absoluteFilePath();
+                childMmpFilename.replace(Option::pro_ext, Option::mmp_ext);
+                sub_name = childMmpFilename;
+                sub_name.replace(Option::mmp_ext, QString(""));
+                sub_name.replace(0, sub_name.lastIndexOf("/") + 1, QString(""));
+                project->values("SHADOW_BLD_INFS").append(QString("bld.inf.") + sub_name);
+            }
+
+            //handle sub project
+            QMakeProject *sub_proj = new QMakeProject(project->properties());
+
+            if (!Option::mkfile::listgen) {
+                for (int ind = 0; ind < sub->indent; ++ind)
+                    printf(" ");
+            }
+
+            sub->input_dir = subdir.absolutePath();
+            if (subdir.isRelative() && old_output_dir != oldpwd) {
+                sub->output_dir = old_output_dir + "/" + subdir.path();
+                printf("Reading %s [%s]\n", subdir.absoluteFilePath().toLatin1().constData(), sub->output_dir.toLatin1().constData());
+            } else {
+                sub->output_dir = sub->input_dir;
+                printf("Reading %s\n", subdir.absoluteFilePath().toLatin1().constData());
+            }
+
+            // find the child mmp filename
+            qmake_setpwd(sub->input_dir);
+
+            QString newpwd = qmake_getpwd();
+
+            Option::output_dir = sub->output_dir;
+            if (Option::output_dir.at(Option::output_dir.length() - 1) != QLatin1Char('/'))
+                Option::output_dir += QLatin1Char('/');
+            sub_proj->read(subdir.fileName());
+            if (!sub_proj->variables()["QMAKE_FAILED_REQUIREMENTS"].isEmpty()) {
+                fprintf(stderr, "Project file(%s) not recursed because all requirements not met:\n\t%s\n",
+                        subdir.fileName().toLatin1().constData(),
+                        sub_proj->values("QMAKE_FAILED_REQUIREMENTS").join(" ").toLatin1().constData());
+                delete sub;
+                delete sub_proj;
+                //continue;
+            } else {
+                // map mmpfile to its absolut filepath
+                mmpPaths.insert(childMmpFilename, newpwd);
+
+                // update mmp files dependency map
+                mmpDependency.insert(parentMmpFilename, childMmpFilename);
+
+                sub->makefile = MetaMakefileGenerator::createMetaGenerator(sub_proj, sub_name);
+                if (0 && sub->makefile->type() == SUBDIRSMETATYPE) {
+                    subs.append(sub);
+                } else {
+                    const QString output_name = Option::output.fileName();
+                    Option::output.setFileName(sub->output_file);
+                    sub->makefile->write(sub->output_dir);
+                    delete sub;
+                    qmakeClearCaches();
+                    sub = 0;
+                    Option::output.setFileName(output_name);
+                }
+            }
+
+            Option::output_dir = old_output_dir;
+            qmake_setpwd(oldpwd);
+
+        }
+        --recurseDepth;
+        Option::output.setFileName(old_output);
+        Option::output_dir = old_output_dir;
+        qmake_setpwd(oldpwd);
+    }
+
+    Subdir *self = new Subdir;
+    self->input_dir = qmake_getpwd();
+
+    // To fully expand find all dependencies:
+    // Do as recursion, then insert result as subdirs data in project
+    QString newpwd = qmake_getpwd();
+    if (!newpwd.endsWith('/'))
+        newpwd += '/';
+    int end = newpwd.size() - 1;
+    int start = newpwd.lastIndexOf("/", end - 2);
+    QString mmpFilename = newpwd.mid(start + 1, end - start - 1);
+    mmpFilename.prepend(newpwd);
+    mmpFilename = mmpFilename.append(Option::mmp_ext);
+
+    // map mmpfile to its absolute filepath
+    mmpPaths.insert(mmpFilename, newpwd);
+
+    QStringList directDependencyList = getDependencyList(mmpFilename, -1);
+    for (int i = 0; i < directDependencyList.size(); ++i) {
+        project->values("MMPFILES_DIRECT_DEPENDS").append(directDependencyList.at(i));
+    }
+
+    QStringList dependencyList = getDependencyList(mmpFilename, 0);
+
+    self->output_dir = Option::output_dir;
+    if (!Option::recursive || (!Option::output.fileName().endsWith(Option::dir_sep) && !QFileInfo(Option::output).isDir()))
+        self->output_file = Option::output.fileName();
+    self->makefile = new BuildsMetaMakefileGenerator(project, name, false);
+    self->makefile->init();
+    subs.append(self);
+
+    return true;
+}
+
+QStringList SymbianSubdirsMetaMakefileGenerator::calculateRelativePaths(QString mmpParent, QStringList mmpChildren)
+{
+    QStringList mmpRelativePaths;
+    QString parentDir = mmpPaths.value(mmpParent);
+    QDir directory(parentDir);
+    for (int i = 0; i < mmpChildren.size(); ++i) {
+        QString childDir = mmpPaths.value(mmpChildren.at(i));
+        if (mmpChildren.at(i) == mmpParent)
+            mmpRelativePaths.append(mmpChildren.at(i));
+        else {
+            QString relativePath = directory.relativeFilePath(childDir);
+            if (relativePath.startsWith(".."))
+                mmpRelativePaths.append(childDir);
+            else
+                directory.relativeFilePath(relativePath);
+        }
+    }
+    return mmpRelativePaths;
+}
+
+//Factory things
+QT_BEGIN_INCLUDE_NAMESPACE
+#include "unixmake.h"
+#include "mingw_make.h"
+#include "projectgenerator.h"
+#include "pbuilder_pbx.h"
+#include "msvc_nmake.h"
+#include "borland_bmake.h"
+#include "msvc_dsp.h"
+#include "msvc_vcproj.h"
+#include "symmake_abld.h"
+#include "symmake_sbsv2.h"
+QT_END_INCLUDE_NAMESPACE
+
+MakefileGenerator *
+MetaMakefileGenerator::createMakefileGenerator(QMakeProject *proj, bool noIO)
+{
+    MakefileGenerator *mkfile = NULL;
+    if(Option::qmake_mode == Option::QMAKE_GENERATE_PROJECT) {
+        mkfile = new ProjectGenerator;
+        mkfile->setProjectFile(proj);
+        return mkfile;
+    }
+
+    QString gen = proj->first("MAKEFILE_GENERATOR");
+    if(gen.isEmpty()) {
+        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",
+                proj->projectFile().toLatin1().constData());
+    } else if(gen == "UNIX") {
+        mkfile = new UnixMakefileGenerator;
+    } else if(gen == "MINGW") {
+        mkfile = new MingwMakefileGenerator;
+    } else if(gen == "PROJECTBUILDER" || gen == "XCODE") {
+        mkfile = new ProjectBuilderMakefileGenerator;
+    } else if(gen == "MSVC") {
+        // Visual Studio =< v6.0
+        if(proj->first("TEMPLATE").indexOf(QRegExp("^vc.*")) != -1)
+            mkfile = new DspMakefileGenerator;
+        else
+            mkfile = new NmakeMakefileGenerator;
+    } else if(gen == "MSVC.NET") {
+        // Visual Studio >= v7.0
+        if(proj->first("TEMPLATE").indexOf(QRegExp("^vc.*")) != -1 || proj->first("TEMPLATE").indexOf(QRegExp("^ce.*")) != -1)
+            mkfile = new VcprojGenerator;
+        else
+            mkfile = new NmakeMakefileGenerator;
+    } else if(gen == "BMAKE") {
+        mkfile = new BorlandMakefileGenerator;
+    } else if(gen == "SYMBIAN_ABLD") {
+        mkfile = new SymbianAbldMakefileGenerator;
+    } else if(gen == "SYMBIAN_SBSV2") {
+        mkfile = new SymbianSbsv2MakefileGenerator;
+    } else {
+        fprintf(stderr, "Unknown generator specified: %s\n", gen.toLatin1().constData());
+    }
+    if (mkfile) {
+        mkfile->setNoIO(noIO);
+        mkfile->setProjectFile(proj);
+    }
+    return mkfile;
+}
+
+MetaMakefileGenerator *
+MetaMakefileGenerator::createMetaGenerator(QMakeProject *proj, const QString &name, bool op, bool *success)
+{
+    MetaMakefileGenerator *ret = 0;
+    if ((Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE ||
+         Option::qmake_mode == Option::QMAKE_GENERATE_PRL)) {
+        if (proj->first("TEMPLATE").endsWith("subdirs"))
+            ret = new SubdirsMetaMakefileGenerator(proj, name, op);
+    }
+    if (!ret)
+        ret = new BuildsMetaMakefileGenerator(proj, name, op);
+    bool res = ret->init();
+    if (success)
+        *success = res;
+    return ret;
+}
+
+QT_END_NAMESPACE