summaryrefslogtreecommitdiffstats
path: root/qmake/generators
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@nokia.com>2009-03-23 09:18:55 (GMT)
committerSimon Hausmann <simon.hausmann@nokia.com>2009-03-23 09:18:55 (GMT)
commite5fcad302d86d316390c6b0f62759a067313e8a9 (patch)
treec2afbf6f1066b6ce261f14341cf6d310e5595bc1 /qmake/generators
downloadQt-e5fcad302d86d316390c6b0f62759a067313e8a9.zip
Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.tar.gz
Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.tar.bz2
Long live Qt 4.5!
Diffstat (limited to 'qmake/generators')
-rw-r--r--qmake/generators/mac/pbuilder_pbx.cpp1860
-rw-r--r--qmake/generators/mac/pbuilder_pbx.h88
-rw-r--r--qmake/generators/makefile.cpp3023
-rw-r--r--qmake/generators/makefile.h267
-rw-r--r--qmake/generators/makefiledeps.cpp963
-rw-r--r--qmake/generators/makefiledeps.h132
-rw-r--r--qmake/generators/metamakefile.cpp490
-rw-r--r--qmake/generators/metamakefile.h77
-rw-r--r--qmake/generators/projectgenerator.cpp510
-rw-r--r--qmake/generators/projectgenerator.h71
-rw-r--r--qmake/generators/unix/unixmake.cpp865
-rw-r--r--qmake/generators/unix/unixmake.h88
-rw-r--r--qmake/generators/unix/unixmake2.cpp1477
-rw-r--r--qmake/generators/win32/borland_bmake.cpp177
-rw-r--r--qmake/generators/win32/borland_bmake.h68
-rw-r--r--qmake/generators/win32/mingw_make.cpp460
-rw-r--r--qmake/generators/win32/mingw_make.h87
-rw-r--r--qmake/generators/win32/msvc_dsp.cpp1207
-rw-r--r--qmake/generators/win32/msvc_dsp.h122
-rw-r--r--qmake/generators/win32/msvc_nmake.cpp322
-rw-r--r--qmake/generators/win32/msvc_nmake.h76
-rw-r--r--qmake/generators/win32/msvc_objectmodel.cpp2636
-rw-r--r--qmake/generators/win32/msvc_objectmodel.h1078
-rw-r--r--qmake/generators/win32/msvc_vcproj.cpp1785
-rw-r--r--qmake/generators/win32/msvc_vcproj.h152
-rw-r--r--qmake/generators/win32/winmakefile.cpp821
-rw-r--r--qmake/generators/win32/winmakefile.h96
-rw-r--r--qmake/generators/xmloutput.cpp340
-rw-r--r--qmake/generators/xmloutput.h210
29 files changed, 19548 insertions, 0 deletions
diff --git a/qmake/generators/mac/pbuilder_pbx.cpp b/qmake/generators/mac/pbuilder_pbx.cpp
new file mode 100644
index 0000000..473a625
--- /dev/null
+++ b/qmake/generators/mac/pbuilder_pbx.cpp
@@ -0,0 +1,1860 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "pbuilder_pbx.h"
+#include "option.h"
+#include "meta.h"
+#include <qdir.h>
+#include <qregexp.h>
+#include <qcryptographichash.h>
+#include <qdebug.h>
+#include <stdlib.h>
+#include <time.h>
+#ifdef Q_OS_UNIX
+# include <sys/types.h>
+# include <sys/stat.h>
+#endif
+#ifdef Q_OS_DARWIN
+#include <ApplicationServices/ApplicationServices.h>
+#include <private/qcore_mac_p.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+//#define GENERATE_AGGREGRATE_SUBDIR
+
+// Note: this is fairly hacky, but it does the job...
+
+static QString qtMD5(const QByteArray &src)
+{
+ QByteArray digest = QCryptographicHash::hash(src, QCryptographicHash::Md5);
+ return QString::fromLatin1(digest.toHex());
+}
+
+ProjectBuilderMakefileGenerator::ProjectBuilderMakefileGenerator() : UnixMakefileGenerator()
+{
+
+}
+
+bool
+ProjectBuilderMakefileGenerator::writeMakefile(QTextStream &t)
+{
+ writingUnixMakefileGenerator = false;
+ if(!project->values("QMAKE_FAILED_REQUIREMENTS").isEmpty()) {
+ /* for now just dump, I need to generated an empty xml or something.. */
+ fprintf(stderr, "Project file not generated because all requirements not met:\n\t%s\n",
+ var("QMAKE_FAILED_REQUIREMENTS").toLatin1().constData());
+ return true;
+ }
+
+ project->values("MAKEFILE").clear();
+ project->values("MAKEFILE").append("Makefile");
+ if(project->first("TEMPLATE") == "app" || project->first("TEMPLATE") == "lib")
+ return writeMakeParts(t);
+ else if(project->first("TEMPLATE") == "subdirs")
+ return writeSubDirs(t);
+ return false;
+}
+
+struct ProjectBuilderSubDirs {
+ QMakeProject *project;
+ QString subdir;
+ bool autoDelete;
+ ProjectBuilderSubDirs(QMakeProject *p, QString s, bool a=true) : project(p), subdir(s), autoDelete(a) { }
+ ~ProjectBuilderSubDirs() {
+ if(autoDelete)
+ delete project;
+ }
+};
+
+bool
+ProjectBuilderMakefileGenerator::writeSubDirs(QTextStream &t)
+{
+ if(project->isActiveConfig("generate_pbxbuild_makefile")) {
+ QString mkwrap = fileFixify(pbx_dir + Option::dir_sep + ".." + Option::dir_sep + project->first("MAKEFILE"),
+ qmake_getpwd());
+ QFile mkwrapf(mkwrap);
+ if(mkwrapf.open(QIODevice::WriteOnly | QIODevice::Text)) {
+ debug_msg(1, "pbuilder: Creating file: %s", mkwrap.toLatin1().constData());
+ QTextStream mkwrapt(&mkwrapf);
+ writingUnixMakefileGenerator = true;
+ UnixMakefileGenerator::writeSubDirs(mkwrapt);
+ writingUnixMakefileGenerator = false;
+ }
+ }
+
+ //HEADER
+ const int pbVersion = pbuilderVersion();
+ t << "// !$*UTF8*$!" << "\n"
+ << "{" << "\n"
+ << "\t" << writeSettings("archiveVersion", "1", SettingsNoQuote) << ";" << "\n"
+ << "\t" << "classes = {" << "\n" << "\t" << "};" << "\n"
+ << "\t" << writeSettings("objectVersion", QString::number(pbVersion), SettingsNoQuote) << ";" << "\n"
+ << "\t" << "objects = {" << endl;
+
+ //SUBDIRS
+ QList<ProjectBuilderSubDirs*> pb_subdirs;
+ pb_subdirs.append(new ProjectBuilderSubDirs(project, QString(), false));
+ QString oldpwd = qmake_getpwd();
+ QMap<QString, QStringList> groups;
+ for(int pb_subdir = 0; pb_subdir < pb_subdirs.size(); ++pb_subdir) {
+ ProjectBuilderSubDirs *pb = pb_subdirs[pb_subdir];
+ const QStringList subdirs = pb->project->values("SUBDIRS");
+ for(int subdir = 0; subdir < subdirs.count(); subdir++) {
+ QString tmp = subdirs[subdir];
+ if(!pb->project->isEmpty(tmp + ".file"))
+ tmp = pb->project->first(tmp + ".file");
+ else if(!pb->project->isEmpty(tmp + ".subdir"))
+ tmp = pb->project->first(tmp + ".subdir");
+ if(fileInfo(tmp).isRelative() && !pb->subdir.isEmpty()) {
+ QString subdir = pb->subdir;
+ if(!subdir.endsWith(Option::dir_sep))
+ subdir += Option::dir_sep;
+ tmp = subdir + tmp;
+ }
+ QFileInfo fi(fileInfo(Option::fixPathToLocalOS(tmp, true)));
+ if(fi.exists()) {
+ if(fi.isDir()) {
+ QString profile = tmp;
+ if(!profile.endsWith(Option::dir_sep))
+ profile += Option::dir_sep;
+ profile += fi.baseName() + ".pro";
+ fi = QFileInfo(profile);
+ }
+ QMakeProject tmp_proj;
+ QString dir = fi.path(), fn = fi.fileName();
+ if(!dir.isEmpty()) {
+ if(!qmake_setpwd(dir))
+ fprintf(stderr, "Cannot find directory: %s\n", dir.toLatin1().constData());
+ }
+ if(tmp_proj.read(fn)) {
+ if(Option::debug_level) {
+ QMap<QString, QStringList> &vars = tmp_proj.variables();
+ for(QMap<QString, QStringList>::Iterator it = vars.begin();
+ it != vars.end(); ++it) {
+ if(it.key().left(1) != "." && !it.value().isEmpty())
+ debug_msg(1, "%s: %s === %s", fn.toLatin1().constData(), it.key().toLatin1().constData(),
+ it.value().join(" :: ").toLatin1().constData());
+ }
+ }
+ if(tmp_proj.first("TEMPLATE") == "subdirs") {
+ QMakeProject *pp = new QMakeProject(&tmp_proj);
+ pp->read(0);
+ pb_subdirs += new ProjectBuilderSubDirs(pp, dir);
+ } else if(tmp_proj.first("TEMPLATE") == "app" || tmp_proj.first("TEMPLATE") == "lib") {
+ QString pbxproj = qmake_getpwd() + Option::dir_sep + tmp_proj.first("TARGET") + projectSuffix();
+ if(!exists(pbxproj)) {
+ warn_msg(WarnLogic, "Ignored (not found) '%s'", pbxproj.toLatin1().constData());
+ goto nextfile; // # Dirty!
+ }
+ const QString project_key = keyFor(pbxproj + "_PROJECTREF");
+ project->values("QMAKE_PBX_SUBDIRS") += pbxproj;
+ //PROJECTREF
+ {
+ bool in_root = true;
+ QString name = qmake_getpwd();
+ if(project->isActiveConfig("flat")) {
+ QString flat_file = fileFixify(name, oldpwd, Option::output_dir, FileFixifyRelative);
+ if(flat_file.indexOf(Option::dir_sep) != -1) {
+ QStringList dirs = flat_file.split(Option::dir_sep);
+ name = dirs.back();
+ }
+ } else {
+ QString flat_file = fileFixify(name, oldpwd, Option::output_dir, FileFixifyRelative);
+ if(QDir::isRelativePath(flat_file) && flat_file.indexOf(Option::dir_sep) != -1) {
+ QString last_grp("QMAKE_SUBDIR_PBX_HEIR_GROUP");
+ QStringList dirs = flat_file.split(Option::dir_sep);
+ name = dirs.back();
+ for(QStringList::Iterator dir_it = dirs.begin(); dir_it != dirs.end(); ++dir_it) {
+ QString new_grp(last_grp + Option::dir_sep + (*dir_it)), new_grp_key(keyFor(new_grp));
+ if(dir_it == dirs.begin()) {
+ if(!groups.contains(new_grp))
+ project->values("QMAKE_SUBDIR_PBX_GROUPS").append(new_grp_key);
+ } else {
+ if(!groups[last_grp].contains(new_grp_key))
+ groups[last_grp] += new_grp_key;
+ }
+ last_grp = new_grp;
+ }
+ groups[last_grp] += project_key;
+ in_root = false;
+ }
+ }
+ if(in_root)
+ project->values("QMAKE_SUBDIR_PBX_GROUPS") += project_key;
+ t << "\t\t" << project_key << " = {" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXFileReference", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("lastKnownFileType", "wrapper.pb-project") << ";" << "\n"
+ << "\t\t\t" << writeSettings("name", escapeFilePath(tmp_proj.first("TARGET") + projectSuffix())) << ";" << "\n"
+ << "\t\t\t" << writeSettings("path", pbxproj) << ";" << "\n"
+ << "\t\t\t" << writeSettings("refType", "0", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("sourceTree", "<absolute>") << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+ //WRAPPER
+ t << "\t\t" << keyFor(pbxproj + "_WRAPPER") << " = {" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXReferenceProxy", SettingsNoQuote) << ";" << "\n";
+ if(tmp_proj.first("TEMPLATE") == "app") {
+ t << "\t\t\t" << writeSettings("fileType", "wrapper.application") << ";" << "\n"
+ << "\t\t\t" << writeSettings("path", tmp_proj.first("TARGET") + ".app") << ";" << "\n";
+ } else {
+ t << "\t\t\t" << writeSettings("fileType", "compiled.mach-o.dylib") << ";" << "\n"
+ << "\t\t\t" << writeSettings("path", tmp_proj.first("TARGET") + ".dylib") << ";" << "\n";
+ }
+ t << "\t\t\t" << writeSettings("refType", "3", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("remoteRef", keyFor(pbxproj + "_WRAPPERREF")) << ";" << "\n"
+ << "\t\t\t" << writeSettings("sourceTree", "BUILT_PRODUCTS_DIR", SettingsNoQuote) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+ t << "\t\t" << keyFor(pbxproj + "_WRAPPERREF") << " = {" << "\n"
+ << "\t\t\t" << writeSettings("containerPortal", project_key) << ";" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXContainerItemProxy", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("proxyType", "2") << ";" << "\n"
+// << "\t\t\t" << writeSettings("remoteGlobalIDString", keyFor(pbxproj + "QMAKE_PBX_REFERENCE")) << ";" << "\n"
+ << "\t\t\t" << writeSettings("remoteGlobalIDString", keyFor(pbxproj + "QMAKE_PBX_REFERENCE!!!")) << ";" << "\n"
+ << "\t\t\t" << writeSettings("remoteInfo", tmp_proj.first("TARGET")) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+ //PRODUCTGROUP
+ t << "\t\t" << keyFor(pbxproj + "_PRODUCTGROUP") << " = {" << "\n"
+ << "\t\t\t" << writeSettings("children", project->values(pbxproj + "_WRAPPER"), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXGroup", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("name", "Products") << ";" << "\n"
+ << "\t\t\t" << writeSettings("refType", "4", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("sourceTree", "<group>") << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+ }
+#ifdef GENERATE_AGGREGRATE_SUBDIR
+ //TARGET (for aggregate)
+ {
+ //container
+ const QString container_proxy = keyFor(pbxproj + "_CONTAINERPROXY");
+ t << "\t\t" << container_proxy << " = {" << "\n"
+ << "\t\t\t" << writeSettings("containerPortal", project_key) << ";" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXContainerItemProxy", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("proxyType", "1") << ";" << "\n"
+ << "\t\t\t" << writeSettings("remoteGlobalIDString", keyFor(pbxproj + "QMAKE_PBX_TARGET")) << ";" << "\n"
+ << "\t\t\t" << writeSettings("remoteInfo", tmp_proj.first("TARGET")) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+ //targetref
+ t << "\t\t" << keyFor(pbxproj + "_TARGETREF") << " = {" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXTargetDependency", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("name", fixForOutput(tmp_proj.first("TARGET") +" (from " + tmp_proj.first("TARGET") + projectSuffix() + ")")) << ";" << "\n"
+ << "\t\t\t" << writeSettings("targetProxy", container_proxy) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+ }
+#endif
+ }
+ }
+ nextfile:
+ qmake_setpwd(oldpwd);
+ }
+ }
+ }
+ qDeleteAll(pb_subdirs);
+ pb_subdirs.clear();
+
+ for(QMap<QString, QStringList>::Iterator grp_it = groups.begin(); grp_it != groups.end(); ++grp_it) {
+ t << "\t\t" << keyFor(grp_it.key()) << " = {" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXGroup", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("children", grp_it.value(), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("name", escapeFilePath(grp_it.key().section(Option::dir_sep, -1))) << ";" << "\n"
+ << "\t\t\t" << writeSettings("refType", "4", SettingsNoQuote) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+ }
+
+ //DUMP EVERYTHING THAT TIES THE ABOVE TOGETHER
+ //BUILDSTYLE
+ QString active_buildstyle;
+ for(int as_release = 0; as_release < 2; as_release++)
+ {
+ QMap<QString, QString> settings;
+ settings.insert("COPY_PHASE_STRIP", (as_release ? "YES" : "NO"));
+ if(as_release)
+ settings.insert("GCC_GENERATE_DEBUGGING_SYMBOLS", "NO");
+ if(project->isActiveConfig("sdk") && !project->isEmpty("QMAKE_MAC_SDK"))
+ settings.insert("SDKROOT", project->first("QMAKE_MAC_SDK"));
+ {
+ const QStringList &l = project->values("QMAKE_MAC_XCODE_SETTINGS");
+ for(int i = 0; i < l.size(); ++i) {
+ QString name = l.at(i);
+ const QString value = project->values(name + QLatin1String(".value")).join(QString(Option::field_sep));
+ if(!project->isEmpty(name + QLatin1String(".name")))
+ name = project->values(name + QLatin1String(".name")).first();
+ settings.insert(name, value);
+ }
+ }
+
+ QString name;
+ if(pbVersion >= 42)
+ name = (as_release ? "Release" : "Debug");
+ else
+ name = (as_release ? "Deployment" : "Development");
+ if(pbVersion >= 42) {
+ QString key = keyFor("QMAKE_SUBDIR_PBX_BUILDCONFIG_" + name);
+ project->values("QMAKE_SUBDIR_PBX_BUILDCONFIGS").append(key);
+ t << "\t\t" << key << " = {" << "\n"
+ << "\t\t\t" << writeSettings("isa", "XCBuildConfiguration", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << "buildSettings = {" << "\n";
+ for(QMap<QString, QString>::Iterator set_it = settings.begin(); set_it != settings.end(); ++set_it)
+ t << "\t\t\t\t" << writeSettings(set_it.key(), set_it.value()) << ";" << "\n";
+ t << "\t\t\t" << "};" << "\n"
+ << "\t\t\t" << writeSettings("name", name) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+ }
+
+ QString key = keyFor("QMAKE_SUBDIR_PBX_BUILDSTYLE_" + name);
+ if(project->isActiveConfig("debug") != (bool)as_release) {
+ project->values("QMAKE_SUBDIR_PBX_BUILDSTYLES").append(key);
+ active_buildstyle = name;
+ } else if(pbVersion >= 42) {
+ project->values("QMAKE_SUBDIR_PBX_BUILDSTYLES").append(key);
+ }
+ t << "\t\t" << key << " = {" << "\n"
+ << "\t\t\t" << writeSettings("buildRules", QStringList(), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << "buildSettings = {" << "\n";
+ for(QMap<QString, QString>::Iterator set_it = settings.begin(); set_it != settings.end(); ++set_it)
+ t << "\t\t\t\t" << writeSettings(set_it.key(), set_it.value()) << ";\n";
+ t << "\t\t\t" << "};" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXBuildStyle", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("name", name) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+ }
+ if(pbVersion >= 42) {
+ t << "\t\t" << keyFor("QMAKE_SUBDIR_PBX_BUILDCONFIG_LIST") << " = {" << "\n"
+ << "\t\t\t" << writeSettings("isa", "XCConfigurationList", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("buildConfigurations", project->values("QMAKE_SUBDIR_PBX_BUILDCONFIGS"), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("defaultConfigurationIsVisible", "0", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("defaultConfigurationIsName", active_buildstyle) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+ }
+
+#ifdef GENERATE_AGGREGRATE_SUBDIR
+ //target
+ t << "\t\t" << keyFor("QMAKE_SUBDIR_PBX_AGGREGATE_TARGET") << " = {" << "\n"
+ << "\t\t\t" << writeSettings("buildPhases", QStringList(), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << "buildSettings = {" << "\n"
+ << "\t\t\t\t" << writeSettings("PRODUCT_NAME", project->values("TARGET").first()) << ";" << "\n"
+ << "\t\t\t" << "};" << "\n";
+ {
+ QStringList dependencies;
+ const QStringList &qmake_subdirs = project->values("QMAKE_PBX_SUBDIRS");
+ for(int i = 0; i < qmake_subdirs.count(); i++)
+ dependencies += keyFor(qmake_subdirs[i] + "_TARGETREF");
+ t << "\t\t\t" << writeSettings("dependencies", dependencies, SettingsAsList, 4) << ";" << "\n"
+ }
+ t << "\t\t\t" << writeSettings("isa", "PBXAggregateTarget", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("name", project->values("TARGET").first()) << ";" << "\n"
+ << "\t\t\t" << writeSettings("productName", project->values("TARGET").first()) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+#endif
+
+ //ROOT_GROUP
+ t << "\t\t" << keyFor("QMAKE_SUBDIR_PBX_ROOT_GROUP") << " = {" << "\n"
+ << "\t\t\t" << writeSettings("children", project->values("QMAKE_SUBDIR_PBX_GROUPS"), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXGroup", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("refType", "4", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("sourceTree", "<group>") << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+
+
+ //ROOT
+ t << "\t\t" << keyFor("QMAKE_SUBDIR_PBX_ROOT") << " = {" << "\n"
+ << "\t\t\t" << "buildSettings = {" << "\n"
+ << "\t\t\t" << "};" << "\n"
+ << "\t\t\t" << writeSettings("buildStyles", project->values("QMAKE_SUBDIR_PBX_BUILDSTYLES"), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXProject", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("mainGroup", keyFor("QMAKE_SUBDIR_PBX_ROOT_GROUP")) << ";" << "\n"
+ << "\t\t\t" << writeSettings("projectDirPath", QStringList()) << ";" << "\n";
+ if(pbVersion >= 42)
+ t << "\t\t\t" << writeSettings("buildConfigurationList", keyFor("QMAKE_SUBDIR_PBX_BUILDCONFIG_LIST")) << ";" << "\n";
+ t << "\t\t\t" << "projectReferences = (" << "\n";
+ {
+ QStringList &qmake_subdirs = project->values("QMAKE_PBX_SUBDIRS");
+ for(int i = 0; i < qmake_subdirs.count(); i++) {
+ QString subdir = qmake_subdirs[i];
+ t << "\t\t\t\t" << "{" << "\n"
+ << "\t\t\t\t\t" << writeSettings("ProductGroup", keyFor(subdir + "_PRODUCTGROUP")) << ";" << "\n"
+ << "\t\t\t\t\t" << writeSettings("ProjectRef", keyFor(subdir + "_PROJECTREF")) << ";" << "\n"
+ << "\t\t\t\t" << "}," << "\n";
+ }
+ }
+ t << "\t\t\t" << ");" << "\n"
+ << "\t\t\t" << writeSettings("targets",
+#ifdef GENERATE_AGGREGRATE_SUBDIR
+ project->values("QMAKE_SUBDIR_AGGREGATE_TARGET"),
+#else
+ QStringList(),
+#endif
+ SettingsAsList, 4) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+
+ //FOOTER
+ t << "\t" << "};" << "\n"
+ << "\t" << writeSettings("rootObject", keyFor("QMAKE_SUBDIR_PBX_ROOT")) << ";" << "\n"
+ << "}" << endl;
+
+ return true;
+}
+
+class ProjectBuilderSources
+{
+ bool buildable, object_output;
+ QString key, group, compiler;
+public:
+ ProjectBuilderSources(const QString &key, bool buildable=false, const QString &group=QString(), const QString &compiler=QString(), bool producesObject=false);
+ QStringList files(QMakeProject *project) const;
+ inline bool isBuildable() const { return buildable; }
+ inline QString keyName() const { return key; }
+ inline QString groupName() const { return group; }
+ inline QString compilerName() const { return compiler; }
+ inline bool isObjectOutput(const QString &file) const {
+ bool ret = object_output;
+ for(int i = 0; !ret && i < Option::c_ext.size(); ++i) {
+ if(file.endsWith(Option::c_ext.at(i))) {
+ ret = true;
+ break;
+ }
+ }
+ for(int i = 0; !ret && i < Option::cpp_ext.size(); ++i) {
+ if(file.endsWith(Option::cpp_ext.at(i))) {
+ ret = true;
+ break;
+ }
+ }
+ return ret;
+ }
+};
+
+ProjectBuilderSources::ProjectBuilderSources(const QString &k, bool b,
+ const QString &g, const QString &c, bool o) : buildable(b), object_output(o), key(k), group(g), compiler(c)
+{
+ if(group.isNull()) {
+ if(k == "SOURCES")
+ group = "Sources";
+ else if(k == "HEADERS")
+ group = "Headers";
+ else if(k == "QMAKE_INTERNAL_INCLUDED_FILES")
+ group = "Sources [qmake]";
+ else if(k == "GENERATED_SOURCES" || k == "GENERATED_FILES")
+ group = "Temporary Sources";
+ else
+ fprintf(stderr, "No group available for %s!\n", k.toLatin1().constData());
+ }
+}
+
+QStringList
+ProjectBuilderSources::files(QMakeProject *project) const
+{
+ QStringList ret = project->values(key);
+ if(key == "QMAKE_INTERNAL_INCLUDED_FILES") {
+ QString pfile = project->projectFile();
+ if(pfile != "(stdin)")
+ ret.prepend(pfile);
+ for(int i = 0; i < ret.size(); ++i) {
+ QStringList newret;
+ if(!ret.at(i).endsWith(Option::prf_ext))
+ newret.append(ret.at(i));
+ ret = newret;
+ }
+ }
+ if(key == "SOURCES" && project->first("TEMPLATE") == "app" && !project->isEmpty("ICON"))
+ ret.append(project->first("ICON"));
+ return ret;
+}
+
+
+bool
+ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
+{
+ QStringList tmp;
+ bool did_preprocess = false;
+
+ //HEADER
+ const int pbVersion = pbuilderVersion();
+ t << "// !$*UTF8*$!" << "\n"
+ << "{" << "\n"
+ << "\t" << writeSettings("archiveVersion", "1", SettingsNoQuote) << ";" << "\n"
+ << "\t" << "classes = {" << "\n" << "\t" << "};" << "\n"
+ << "\t" << writeSettings("objectVersion", QString::number(pbVersion), SettingsNoQuote) << ";" << "\n"
+ << "\t" << "objects = {" << endl;
+
+ //MAKE QMAKE equivelant
+ if(!project->isActiveConfig("no_autoqmake") && project->projectFile() != "(stdin)") {
+ QString mkfile = pbx_dir + Option::dir_sep + "qt_makeqmake.mak";
+ QFile mkf(mkfile);
+ if(mkf.open(QIODevice::WriteOnly | QIODevice::Text)) {
+ writingUnixMakefileGenerator = true;
+ debug_msg(1, "pbuilder: Creating file: %s", mkfile.toLatin1().constData());
+ QTextStream mkt(&mkf);
+ writeHeader(mkt);
+ mkt << "QMAKE = " << (project->isEmpty("QMAKE_QMAKE") ?
+ QString((QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qmake")) :
+ var("QMAKE_QMAKE")) << endl;
+ writeMakeQmake(mkt);
+ mkt.flush();
+ mkf.close();
+ writingUnixMakefileGenerator = false;
+ }
+ QString phase_key = keyFor("QMAKE_PBX_MAKEQMAKE_BUILDPHASE");
+ mkfile = fileFixify(mkfile, qmake_getpwd());
+ project->values("QMAKE_PBX_PRESCRIPT_BUILDPHASES").append(phase_key);
+ t << "\t\t" << phase_key << " = {" << "\n"
+ << "\t\t\t" << writeSettings("buildActionMask", "2147483647", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("files", QStringList(), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("generatedFileNames", QStringList(), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXShellScriptBuildPhase", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("name", "Qt Qmake") << ";" << "\n"
+ << "\t\t\t" << writeSettings("neededFileNames", QStringList(), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("shellPath", "/bin/sh") << ";" << "\n"
+ << "\t\t\t" << writeSettings("shellScript", fixForOutput("make -C " + escapeFilePath(qmake_getpwd()) + " -f " + escapeFilePath(mkfile))) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+ }
+
+ //DUMP SOURCES
+ QMap<QString, QStringList> groups;
+ QList<ProjectBuilderSources> sources;
+ sources.append(ProjectBuilderSources("SOURCES", true));
+ sources.append(ProjectBuilderSources("GENERATED_SOURCES", true));
+ sources.append(ProjectBuilderSources("GENERATED_FILES"));
+ sources.append(ProjectBuilderSources("HEADERS"));
+ sources.append(ProjectBuilderSources("QMAKE_INTERNAL_INCLUDED_FILES"));
+ if(!project->isEmpty("QMAKE_EXTRA_COMPILERS")) {
+ const QStringList &quc = project->values("QMAKE_EXTRA_COMPILERS");
+ for(QStringList::ConstIterator it = quc.begin(); it != quc.end(); ++it) {
+ QString tmp_out = project->first((*it) + ".output");
+ if(project->isEmpty((*it) + ".output"))
+ continue;
+ QString name = (*it);
+ if(!project->isEmpty((*it) + ".name"))
+ name = project->first((*it) + ".name");
+ const QStringList &inputs = project->values((*it) + ".input");
+ for(int input = 0; input < inputs.size(); ++input) {
+ if(project->isEmpty(inputs.at(input)))
+ continue;
+ bool duplicate = false;
+ for(int i = 0; i < sources.size(); ++i) {
+ if(sources.at(i).keyName() == inputs.at(input)) {
+ duplicate = true;
+ break;
+ }
+ }
+ if(!duplicate) {
+ bool isObj = project->values((*it) + ".CONFIG").indexOf("no_link") == -1;
+ const QStringList &outputs = project->values((*it) + ".variable_out");
+ for(int output = 0; output < outputs.size(); ++output) {
+ if(outputs.at(output) != "OBJECT") {
+ isObj = false;
+ break;
+ }
+ }
+ sources.append(ProjectBuilderSources(inputs.at(input), true,
+ QString("Sources [") + name + "]", (*it), isObj));
+ }
+ }
+ }
+ }
+ for(int source = 0; source < sources.size(); ++source) {
+ QStringList &src_list = project->values("QMAKE_PBX_" + sources.at(source).keyName());
+ QStringList &root_group_list = project->values("QMAKE_PBX_GROUPS");
+
+ QStringList files = fileFixify(sources.at(source).files(project));
+ for(int f = 0; f < files.count(); ++f) {
+ QString file = files[f];
+ if(file.length() >= 2 && (file[0] == '"' || file[0] == '\'') && file[(int) file.length()-1] == file[0])
+ file = file.mid(1, file.length()-2);
+ if(!sources.at(source).compilerName().isNull() &&
+ !verifyExtraCompiler(sources.at(source).compilerName(), file))
+ continue;
+ if(file.endsWith(Option::prl_ext))
+ continue;
+
+ bool in_root = true;
+ QString src_key = keyFor(file), name = file;
+ if(project->isActiveConfig("flat")) {
+ QString flat_file = fileFixify(file, qmake_getpwd(), Option::output_dir, FileFixifyRelative);
+ if(flat_file.indexOf(Option::dir_sep) != -1) {
+ QStringList dirs = flat_file.split(Option::dir_sep);
+ name = dirs.back();
+ }
+ } else {
+ QString flat_file = fileFixify(file, qmake_getpwd(), Option::output_dir, FileFixifyRelative);
+ if(QDir::isRelativePath(flat_file) && flat_file.indexOf(Option::dir_sep) != -1) {
+ QString last_grp("QMAKE_PBX_" + sources.at(source).groupName() + "_HEIR_GROUP");
+ QStringList dirs = flat_file.split(Option::dir_sep);
+ name = dirs.back();
+ dirs.pop_back(); //remove the file portion as it will be added via src_key
+ for(QStringList::Iterator dir_it = dirs.begin(); dir_it != dirs.end(); ++dir_it) {
+ QString new_grp(last_grp + Option::dir_sep + (*dir_it)), new_grp_key(keyFor(new_grp));
+ if(dir_it == dirs.begin()) {
+ if(!src_list.contains(new_grp_key))
+ src_list.append(new_grp_key);
+ } else {
+ if(!groups[last_grp].contains(new_grp_key))
+ groups[last_grp] += new_grp_key;
+ }
+ last_grp = new_grp;
+ }
+ groups[last_grp] += src_key;
+ in_root = false;
+ }
+ }
+ if(in_root)
+ src_list.append(src_key);
+ //source reference
+ t << "\t\t" << src_key << " = {" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXFileReference", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("name", escapeFilePath(name)) << ";" << "\n"
+ << "\t\t\t" << writeSettings("path", escapeFilePath(file)) << ";" << "\n"
+ << "\t\t\t" << writeSettings("refType", QString::number(reftypeForFile(file)), SettingsNoQuote) << ";" << "\n";
+ if(pbVersion >= 38) {
+ QString filetype;
+ for(QStringList::Iterator cppit = Option::cpp_ext.begin(); cppit != Option::cpp_ext.end(); ++cppit) {
+ if(file.endsWith((*cppit))) {
+ filetype = "sourcecode.cpp.cpp";
+ break;
+ }
+ }
+ if(!filetype.isNull())
+ t << "\t\t\t" << writeSettings("lastKnownFileType", filetype) << ";" << "\n";
+ }
+ t << "\t\t" << "};" << "\n";
+ if(sources.at(source).isBuildable()) { //build reference
+ QString build_key = keyFor(file + ".BUILDABLE");
+ t << "\t\t" << build_key << " = {" << "\n"
+ << "\t\t\t" << writeSettings("fileRef", src_key) << ";" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXBuildFile", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << "settings = {" << "\n"
+ << "\t\t\t\t" << writeSettings("ATTRIBUTES", QStringList(), SettingsAsList, 5) << ";" << "\n"
+ << "\t\t\t" << "};" << "\n"
+ << "\t\t" << "};" << "\n";
+ if(sources.at(source).isObjectOutput(file))
+ project->values("QMAKE_PBX_OBJ").append(build_key);
+ }
+ }
+ if(!src_list.isEmpty()) {
+ QString group_key = keyFor(sources.at(source).groupName());
+ if(root_group_list.indexOf(group_key) == -1)
+ root_group_list += group_key;
+
+ QStringList &group = groups[sources.at(source).groupName()];
+ for(int src = 0; src < src_list.size(); ++src) {
+ if(group.indexOf(src_list.at(src)) == -1)
+ group += src_list.at(src);
+ }
+ }
+ }
+ for(QMap<QString, QStringList>::Iterator grp_it = groups.begin(); grp_it != groups.end(); ++grp_it) {
+ t << "\t\t" << keyFor(grp_it.key()) << " = {" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXGroup", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("children", grp_it.value(), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("name", escapeFilePath(grp_it.key().section(Option::dir_sep, -1))) << ";" << "\n"
+ << "\t\t\t" << writeSettings("refType", "4", SettingsNoQuote) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+ }
+
+ //PREPROCESS BUILDPHASE (just a makefile)
+ {
+ QString mkfile = pbx_dir + Option::dir_sep + "qt_preprocess.mak";
+ QFile mkf(mkfile);
+ if(mkf.open(QIODevice::WriteOnly | QIODevice::Text)) {
+ writingUnixMakefileGenerator = true;
+ did_preprocess = true;
+ debug_msg(1, "pbuilder: Creating file: %s", mkfile.toLatin1().constData());
+ QTextStream mkt(&mkf);
+ writeHeader(mkt);
+ mkt << "MOC = " << Option::fixPathToTargetOS(var("QMAKE_MOC")) << endl;
+ mkt << "UIC = " << Option::fixPathToTargetOS(var("QMAKE_UIC")) << endl;
+ mkt << "LEX = " << var("QMAKE_LEX") << endl;
+ mkt << "LEXFLAGS = " << var("QMAKE_LEXFLAGS") << endl;
+ mkt << "YACC = " << var("QMAKE_YACC") << endl;
+ mkt << "YACCFLAGS = " << var("QMAKE_YACCFLAGS") << endl;
+ mkt << "DEFINES = "
+ << varGlue("PRL_EXPORT_DEFINES","-D"," -D"," ")
+ << varGlue("DEFINES","-D"," -D","") << endl;
+ mkt << "INCPATH = " << "-I" << specdir();
+ if(!project->isActiveConfig("no_include_pwd")) {
+ QString pwd = escapeFilePath(fileFixify(qmake_getpwd()));
+ if(pwd.isEmpty())
+ pwd = ".";
+ mkt << " -I" << pwd;
+ }
+ {
+ const QStringList &incs = project->values("INCLUDEPATH");
+ for(QStringList::ConstIterator incit = incs.begin(); incit != incs.end(); ++incit)
+ mkt << " " << "-I" << escapeFilePath((*incit));
+ }
+ if(!project->isEmpty("QMAKE_FRAMEWORKPATH_FLAGS"))
+ mkt << " " << var("QMAKE_FRAMEWORKPATH_FLAGS");
+ mkt << endl;
+ mkt << "DEL_FILE = " << var("QMAKE_DEL_FILE") << endl;
+ mkt << "MOVE = " << var("QMAKE_MOVE") << endl << endl;
+ mkt << "IMAGES = " << varList("QMAKE_IMAGE_COLLECTION") << endl;
+ mkt << "PARSERS =";
+ if(!project->isEmpty("YACCSOURCES")) {
+ QStringList &yaccs = project->values("YACCSOURCES");
+ for(QStringList::Iterator yit = yaccs.begin(); yit != yaccs.end(); ++yit) {
+ QFileInfo fi(fileInfo((*yit)));
+ mkt << " " << fi.path() << Option::dir_sep << fi.baseName()
+ << Option::yacc_mod << Option::cpp_ext.first();
+ }
+ }
+ if(!project->isEmpty("LEXSOURCES")) {
+ QStringList &lexs = project->values("LEXSOURCES");
+ for(QStringList::Iterator lit = lexs.begin(); lit != lexs.end(); ++lit) {
+ QFileInfo fi(fileInfo((*lit)));
+ mkt << " " << fi.path() << Option::dir_sep << fi.baseName()
+ << Option::lex_mod << Option::cpp_ext.first();
+ }
+ }
+ mkt << "\n";
+ mkt << "preprocess: $(PARSERS) compilers" << endl;
+ mkt << "clean preprocess_clean: parser_clean compiler_clean" << endl << endl;
+ mkt << "parser_clean:" << "\n";
+ if(!project->isEmpty("YACCSOURCES") || !project->isEmpty("LEXSOURCES"))
+ mkt << "\t-rm -f $(PARSERS)" << "\n";
+ writeExtraTargets(mkt);
+ if(!project->isEmpty("QMAKE_EXTRA_COMPILERS")) {
+ mkt << "compilers:";
+ const QStringList &compilers = project->values("QMAKE_EXTRA_COMPILERS");
+ for(int compiler = 0; compiler < compilers.size(); ++compiler) {
+ QString tmp_out = project->first(compilers.at(compiler) + ".output");
+ if(project->isEmpty(compilers.at(compiler) + ".output"))
+ continue;
+ const QStringList &inputs = project->values(compilers.at(compiler) + ".input");
+ for(int input = 0; input < inputs.size(); ++input) {
+ if(project->isEmpty(inputs.at(input)))
+ continue;
+ const QStringList &files = project->values(inputs.at(input));
+ for(int file = 0, added = 0; file < files.size(); ++file) {
+ if(!verifyExtraCompiler(compilers.at(compiler), files.at(file)))
+ continue;
+ if(added && !(added % 3))
+ mkt << "\\\n\t";
+ ++added;
+ const QString file_name = fileFixify(files.at(file), Option::output_dir, Option::output_dir);
+ mkt << " " << replaceExtraCompilerVariables(tmp_out, file_name, QString());
+ }
+ }
+ }
+ mkt << endl;
+ writeExtraCompilerTargets(mkt);
+ writingUnixMakefileGenerator = false;
+ }
+ mkt.flush();
+ mkf.close();
+ }
+ mkfile = fileFixify(mkfile, qmake_getpwd());
+ QString phase_key = keyFor("QMAKE_PBX_PREPROCESS_TARGET");
+// project->values("QMAKE_PBX_BUILDPHASES").append(phase_key);
+ project->values("QMAKE_PBX_PRESCRIPT_BUILDPHASES").append(phase_key);
+ t << "\t\t" << phase_key << " = {" << "\n"
+ << "\t\t\t" << writeSettings("buildActionMask", "2147483647", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("files", QStringList(), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("generatedFileNames", fixListForOutput("QMAKE_PBX_OBJ"), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXShellScriptBuildPhase", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("name", "Qt Preprocessors") << ";" << "\n"
+ << "\t\t\t" << writeSettings("neededFileNames", fixListForOutput("QMAKE_PBX_OBJ"), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("shellPath", "/bin/sh") << ";" << "\n"
+ << "\t\t\t" << writeSettings("shellScript", fixForOutput("make -C " + escapeFilePath(qmake_getpwd()) + " -f " + escapeFilePath(mkfile))) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+ }
+
+ //SOURCE BUILDPHASE
+ if(!project->isEmpty("QMAKE_PBX_OBJ")) {
+ QString grp = "Build Sources", key = keyFor(grp);
+ project->values("QMAKE_PBX_BUILDPHASES").append(key);
+ t << "\t\t" << key << " = {" << "\n"
+ << "\t\t\t" << writeSettings("buildActionMask", "2147483647", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("files", fixListForOutput("QMAKE_PBX_OBJ"), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXSourcesBuildPhase", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("name", grp) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+ }
+
+ if(!project->isActiveConfig("staticlib")) { //DUMP LIBRARIES
+ QStringList &libdirs = project->values("QMAKE_PBX_LIBPATHS"),
+ &frameworkdirs = project->values("QMAKE_FRAMEWORKPATH");
+ QString libs[] = { "QMAKE_LFLAGS", "QMAKE_LIBDIR_FLAGS", "QMAKE_FRAMEWORKPATH_FLAGS",
+ "QMAKE_LIBS", QString() };
+ for(int i = 0; !libs[i].isNull(); i++) {
+ tmp = project->values(libs[i]);
+ for(int x = 0; x < tmp.count();) {
+ bool remove = false;
+ QString library, name, opt = tmp[x].trimmed();
+ if(opt.length() >= 2 && (opt[0] == '"' || opt[0] == '\'') &&
+ opt[(int) opt.length()-1] == opt[0])
+ opt = opt.mid(1, opt.length()-2);
+ if(opt.startsWith("-L")) {
+ QString r = opt.right(opt.length() - 2);
+ fixForOutput(r);
+ libdirs.append(r);
+ } else if(opt == "-prebind") {
+ project->values("QMAKE_DO_PREBINDING").append("TRUE");
+ remove = true;
+ } else if(opt.startsWith("-l")) {
+ name = opt.right(opt.length() - 2);
+ QString lib("lib" + name);
+ for(QStringList::Iterator lit = libdirs.begin(); lit != libdirs.end(); ++lit) {
+ if(project->isActiveConfig("link_prl")) {
+ /* This isn't real nice, but it is real useful. This looks in a prl
+ for what the library will ultimately be called so we can stick it
+ in the ProjectFile. If the prl format ever changes (not likely) then
+ this will not really work. However, more concerning is that it will
+ encode the version number in the Project file which might be a bad
+ things in days to come? --Sam
+ */
+ QString lib_file = (*lit) + Option::dir_sep + lib;
+ if(QMakeMetaInfo::libExists(lib_file)) {
+ QMakeMetaInfo libinfo;
+ if(libinfo.readLib(lib_file)) {
+ if(!libinfo.isEmpty("QMAKE_PRL_TARGET")) {
+ library = (*lit) + Option::dir_sep + libinfo.first("QMAKE_PRL_TARGET");
+ debug_msg(1, "pbuilder: Found library (%s) via PRL %s (%s)",
+ opt.toLatin1().constData(), lib_file.toLatin1().constData(), library.toLatin1().constData());
+ remove = true;
+ }
+ }
+ }
+ }
+ if(!remove) {
+ QString extns[] = { ".dylib", ".so", ".a", QString() };
+ for(int n = 0; !remove && !extns[n].isNull(); n++) {
+ QString tmp = (*lit) + Option::dir_sep + lib + extns[n];
+ if(exists(tmp)) {
+ library = tmp;
+ debug_msg(1, "pbuilder: Found library (%s) via %s",
+ opt.toLatin1().constData(), library.toLatin1().constData());
+ remove = true;
+ }
+ }
+ }
+ }
+ } else if(opt.startsWith("-F")) {
+ QString r;
+ if(opt.size() > 2) {
+ r = opt.right(opt.length() - 2);
+ } else {
+ if(x == tmp.count()-1)
+ break;
+ r = tmp[++x];
+ }
+ if(!r.isEmpty()) {
+ fixForOutput(r);
+ frameworkdirs.append(r);
+ }
+ } else if(opt == "-framework") {
+ if(x == tmp.count()-1)
+ break;
+ const QString framework = tmp[x+1];
+ QStringList fdirs = frameworkdirs;
+ fdirs << "/System/Library/Frameworks/" << "/Library/Frameworks/";
+ for(int fdir = 0; fdir < fdirs.count(); fdir++) {
+ if(exists(fdirs[fdir] + QDir::separator() + framework + ".framework")) {
+ tmp.removeAt(x);
+ remove = true;
+ library = fdirs[fdir] + Option::dir_sep + framework + ".framework";
+ break;
+ }
+ }
+ } else if(opt.left(1) != "-") {
+ if(exists(opt)) {
+ remove = true;
+ library = opt;
+ }
+ }
+ if(!library.isEmpty()) {
+ const int slsh = library.lastIndexOf(Option::dir_sep);
+ if(name.isEmpty()) {
+ if(slsh != -1)
+ name = library.right(library.length() - slsh - 1);
+ }
+ if(slsh != -1) {
+ const QString path = QFileInfo(library.left(slsh)).absoluteFilePath();
+ if(!path.isEmpty() && !libdirs.contains(path))
+ libdirs += path;
+ }
+ library = fileFixify(library);
+ QString key = keyFor(library);
+ bool is_frmwrk = (library.endsWith(".framework"));
+ t << "\t\t" << key << " = {" << "\n"
+ << "\t\t\t" << writeSettings("isa", (is_frmwrk ? "PBXFrameworkReference" : "PBXFileReference"), SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("name", escapeFilePath(name)) << ";" << "\n"
+ << "\t\t\t" << writeSettings("path", escapeFilePath(library)) << ";" << "\n"
+ << "\t\t\t" << writeSettings("refType", QString::number(reftypeForFile(library)), SettingsNoQuote) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+ project->values("QMAKE_PBX_LIBRARIES").append(key);
+ QString build_key = keyFor(library + ".BUILDABLE");
+ t << "\t\t" << build_key << " = {" << "\n"
+ << "\t\t\t" << writeSettings("fileRef", key) << ";" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXBuildFile", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << "settings = {" << "\n"
+ << "\t\t\t" << "};" << "\n"
+ << "\t\t" << "};" << "\n";
+ project->values("QMAKE_PBX_BUILD_LIBRARIES").append(build_key);
+ }
+ if(remove)
+ tmp.removeAt(x);
+ else
+ x++;
+ }
+ project->values(libs[i]) = tmp;
+ }
+ }
+ //SUBLIBS BUILDPHASE (just another makefile)
+ if(!project->isEmpty("SUBLIBS")) {
+ QString mkfile = pbx_dir + Option::dir_sep + "qt_sublibs.mak";
+ QFile mkf(mkfile);
+ if(mkf.open(QIODevice::WriteOnly | QIODevice::Text)) {
+ writingUnixMakefileGenerator = true;
+ debug_msg(1, "pbuilder: Creating file: %s", mkfile.toLatin1().constData());
+ QTextStream mkt(&mkf);
+ writeHeader(mkt);
+ mkt << "SUBLIBS= ";
+ tmp = project->values("SUBLIBS");
+ for(int i = 0; i < tmp.count(); i++)
+ t << "tmp/lib" << tmp[i] << ".a ";
+ t << endl << endl;
+ mkt << "sublibs: $(SUBLIBS)" << endl << endl;
+ tmp = project->values("SUBLIBS");
+ for(int i = 0; i < tmp.count(); i++)
+ t << "tmp/lib" << tmp[i] << ".a" << ":\n\t"
+ << var(QString("MAKELIB") + tmp[i]) << endl << endl;
+ mkt.flush();
+ mkf.close();
+ writingUnixMakefileGenerator = false;
+ }
+ QString phase_key = keyFor("QMAKE_PBX_SUBLIBS_BUILDPHASE");
+ mkfile = fileFixify(mkfile, qmake_getpwd());
+ project->values("QMAKE_PBX_PRESCRIPT_BUILDPHASES").append(phase_key);
+ t << "\t\t" << phase_key << " = {" << "\n"
+ << "\t\t\t" << writeSettings("buildActionMask", "2147483647", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("files", QStringList(), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("generatedFileNames", QStringList(), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXShellScriptBuildPhase", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("name", "Qt Sublibs") << ";" << "\n"
+ << "\t\t\t" << writeSettings("neededFileNames", QStringList(), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("shellPath", "/bin/sh") << "\n"
+ << "\t\t\t" << writeSettings("shellScript", fixForOutput("make -C " + escapeFilePath(qmake_getpwd()) + " -f " + escapeFilePath(mkfile))) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+ }
+ //LIBRARY BUILDPHASE
+ if(!project->isEmpty("QMAKE_PBX_LIBRARIES")) {
+ tmp = project->values("QMAKE_PBX_LIBRARIES");
+ if(!tmp.isEmpty()) {
+ QString grp("External Frameworks and Libraries"), key = keyFor(grp);
+ project->values("QMAKE_PBX_GROUPS").append(key);
+ t << "\t\t" << key << " = {" << "\n"
+ << "\t\t\t" << writeSettings("children", project->values("QMAKE_PBX_LIBRARIES"), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXGroup", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("name", escapeFilePath(grp)) << ";" << "\n"
+ << "\t\t\t" << writeSettings("path", QStringList()) << ";" << "\n"
+ << "\t\t\t" << writeSettings("refType", "4", SettingsNoQuote) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+ }
+ }
+ {
+ QString grp("Frameworks & Libraries"), key = keyFor(grp);
+ project->values("QMAKE_PBX_BUILDPHASES").append(key);
+ t << "\t\t" << key << " = {" << "\n"
+ << "\t\t\t" << writeSettings("buildActionMask", "2147483647", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("files", project->values("QMAKE_PBX_BUILD_LIBRARIES"), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXFrameworksBuildPhase", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("name", escapeFilePath(grp)) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+ }
+ if(project->isActiveConfig("app_bundle") && project->first("TEMPLATE") == "app") { //BUNDLE RESOURCES
+ QString grp("Bundle Resources"), key = keyFor(grp);
+ project->values("QMAKE_PBX_BUILDPHASES").append(key);
+ t << "\t\t" << key << " = {" << "\n"
+ << "\t\t\t" << writeSettings("buildActionMask", "2147483647", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << "files = (" << "\n";
+ if(!project->isEmpty("ICON")) {
+ QString icon = project->first("ICON");
+ if(icon.length() >= 2 && (icon[0] == '"' || icon[0] == '\'') && icon[(int)icon.length()-1] == icon[0])
+ icon = icon.mid(1, icon.length()-2);
+ t << "\t\t\t\t" << keyFor(icon + ".BUILDABLE") << ",\n";
+ }
+ t << "\t\t\t" << ");" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXResourcesBuildPhase", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("name", escapeFilePath(grp)) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+ }
+ { //INSTALL BUILDPHASE (copy)
+ QString phase_key = keyFor("QMAKE_PBX_TARGET_COPY_PHASE");
+ QString destDir = Option::output_dir;
+ if (!project->isEmpty("QMAKE_ORIG_DESTDIR"))
+ destDir = project->first("QMAKE_ORIG_DESTDIR");
+ destDir = fixForOutput(destDir);
+ destDir = fileInfo(Option::fixPathToLocalOS(destDir)).absoluteFilePath();
+ project->values("QMAKE_PBX_PRESCRIPT_BUILDPHASES").append(phase_key);
+ t << "\t\t" << phase_key << " = {\n"
+ << "\t\t\t" << writeSettings("name", "Project Copy") << ";" << "\n"
+ << "\t\t\t" << writeSettings("buildActionMask", "2147483647", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("dstPath", escapeFilePath(destDir)) << ";" << "\n"
+ << "\t\t\t" << writeSettings("dstSubfolderSpec", "0", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("files", keyFor("QMAKE_PBX_TARGET_COPY_FILE"), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXCopyFilesBuildPhase", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("runOnlyForDeploymentPostprocessing", "0", SettingsNoQuote) << ";" << "\n"
+ << "\t\t" << "};\n"
+ << "\t\t" << keyFor("QMAKE_PBX_TARGET_COPY_FILE") << " = {\n"
+ << "\t\t\t" << writeSettings("fileRef", keyFor(pbx_dir + "QMAKE_PBX_REFERENCE")) << ";" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXBuildFile", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << "settings = {\n"
+ << "\t\t\t" << "};\n"
+ << "\t\t" << "};\n";
+ }
+ //BUNDLE_DATA BUILDPHASE (copy)
+ if(!project->isEmpty("QMAKE_BUNDLE_DATA")) {
+ QStringList bundle_file_refs;
+ //all bundle data
+ const QStringList &bundle_data = project->values("QMAKE_BUNDLE_DATA");
+ for(int i = 0; i < bundle_data.count(); i++) {
+ QStringList pbx_files;
+ //all files
+ const QStringList &files = project->values(bundle_data[i] + ".files");
+ for(int file = 0; file < files.count(); file++) {
+ QString file_ref_key = keyFor("QMAKE_PBX_BUNDLE_COPY_FILE_REF." + bundle_data[i] + "-" + files[file]);
+ bundle_file_refs += file_ref_key;
+ t << "\t\t" << file_ref_key << " = {" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXFileReference", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("path", escapeFilePath(files[file])) << ";" << "\n"
+ << "\t\t\t" << writeSettings("refType", QString::number(reftypeForFile(files[file])), SettingsNoQuote) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+ QString copy_file_key = keyFor("QMAKE_PBX_BUNDLE_COPY_FILE." + bundle_data[i] + "-" + files[file]);
+ pbx_files += copy_file_key;
+ t << "\t\t" << copy_file_key << " = {\n"
+ << "\t\t\t" << writeSettings("fileRef", file_ref_key) << ";" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXBuildFile", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << "settings = {\n"
+ << "\t\t\t" << "}" << ";" << "\n"
+ << "\t\t" << "}" << ";" << "\n";
+ }
+ //the phase
+ QString phase_key = keyFor("QMAKE_PBX_BUNDLE_COPY." + bundle_data[i]);
+ QString path;
+ if(!project->isEmpty(bundle_data[i] + ".version")) {
+ //###
+ }
+ path += project->first(bundle_data[i] + ".path");
+ project->values("QMAKE_PBX_PRESCRIPT_BUILDPHASES").append(phase_key);
+ t << "\t\t" << phase_key << " = {\n"
+ << "\t\t\t" << writeSettings("name", "Bundle Copy [" + bundle_data[i] + "]") << ";" << "\n"
+ << "\t\t\t" << writeSettings("buildActionMask", "2147483647", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("dstPath", escapeFilePath(path)) << ";" << "\n"
+ << "\t\t\t" << writeSettings("dstSubfolderSpec", "1", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("files", pbx_files, SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXCopyFilesBuildPhase", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("runOnlyForDeploymentPostprocessing", "0", SettingsNoQuote) << ";" << "\n"
+ << "\t\t" << "}" << ";" << "\n";
+ }
+ QString bundle_copy_key = keyFor("QMAKE_PBX_BUNDLE_COPY");
+ project->values("QMAKE_PBX_GROUPS").append(bundle_copy_key);
+ t << "\t\t" << bundle_copy_key << " = {" << "\n"
+ << "\t\t\t" << writeSettings("children", bundle_file_refs, SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXGroup", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("name", "Source [bundle data]") << ";" << "\n"
+ << "\t\t\t" << writeSettings("path", QStringList()) << ";" << "\n"
+ << "\t\t\t" << writeSettings("refType", "4", SettingsNoQuote) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+ }
+
+ if(/*pbVersion >= 38 &&*/ !project->isEmpty("QMAKE_PBX_PRESCRIPT_BUILDPHASES") && 0) {
+ // build reference
+ t << "\t\t" << keyFor("QMAKE_PBX_PRESCRIPT_BUILDREFERENCE") << " = {" << "\n"
+ << "\t\t\t" << writeSettings("includeInIndex", "0") << ";" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXFileReference", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("path", "preprocessor.out") << ";" << "\n"
+ << "\t\t\t" << writeSettings("refType", "3", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("sourceTree", "BUILT_PRODUCTS_DIR", SettingsNoQuote) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+ project->values("QMAKE_PBX_PRODUCTS").append(keyFor("QMAKE_PBX_PRESCRIPTS_BUILDREFERENCE"));
+ //build phase
+ t << "\t\t" << keyFor("QMAKE_PBX_PRESCRIPTS_BUILDPHASE") << " = {" << "\n"
+ << "\t\t\t" << writeSettings("buildPhases", project->values("QMAKE_PBX_PRESCRIPT_BUILDPHASES"), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("buildRules", QStringList(), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("buildSettings", QStringList(), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("dependencies", QStringList(), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXNativeTarget", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("name", "Qt Preprocessor Steps") << ";" << "\n"
+ << "\t\t\t" << writeSettings("productName", "Qt Preprocessor Steps") << ";" << "\n"
+ << "\t\t\t" << writeSettings("productReference", keyFor("QMAKE_PBX_PRESCRIPTS_BUILDREFERENCE")) << ";" << "\n";
+ if(!project->isEmpty("QMAKE_PBX_PRODUCT_TYPE"))
+ t << "\t\t\t" << writeSettings("productType", project->first("QMAKE_PBX_PRODUCT_TYPE")) << ";" << "\n";
+ else
+ t << "\t\t\t" << writeSettings("productType", "com.apple.product-type.tool") << ";" << "\n";
+ t << "\t\t" << "};" << "\n";
+ //dependency
+ t << "\t\t" << keyFor("QMAKE_PBX_PRESCRIPTS_DEPENDENCY") << " = {" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXTargetDependency", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("target", keyFor("QMAKE_PBX_PRESCRIPTS_BUILDPHASE")) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+ project->values("QMAKE_PBX_TARGET_DEPENDS").append(keyFor("QMAKE_PBX_PRESCRIPTS_DEPENDENCY"));
+ project->values("QMAKE_PBX_PRESCRIPT_BUILDPHASES").clear(); //these are already consumed above
+ }
+
+ //DUMP EVERYTHING THAT TIES THE ABOVE TOGETHER
+ //ROOT_GROUP
+ t << "\t\t" << keyFor("QMAKE_PBX_ROOT_GROUP") << " = {" << "\n"
+ << "\t\t\t" << writeSettings("children", project->values("QMAKE_PBX_GROUPS"), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXGroup", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("name", escapeFilePath(project->first("QMAKE_ORIG_TARGET"))) << ";" << "\n"
+ << "\t\t\t" << writeSettings("path", QStringList()) << ";" << "\n"
+ << "\t\t\t" << writeSettings("refType", "4", SettingsNoQuote) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+ //REFERENCE
+ project->values("QMAKE_PBX_PRODUCTS").append(keyFor(pbx_dir + "QMAKE_PBX_REFERENCE"));
+ t << "\t\t" << keyFor(pbx_dir + "QMAKE_PBX_REFERENCE") << " = {" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXFileReference", SettingsNoQuote) << ";" << "\n";
+ if(project->first("TEMPLATE") == "app") {
+ QString targ = project->first("QMAKE_ORIG_TARGET");
+ if(project->isActiveConfig("bundle") && !project->isEmpty("QMAKE_BUNDLE_EXTENSION")) {
+ if(!project->isEmpty("QMAKE_BUNDLE_NAME"))
+ targ = project->first("QMAKE_BUNDLE_NAME");
+ targ += project->first("QMAKE_BUNDLE_EXTENSION");
+ if(!project->isEmpty("QMAKE_PBX_BUNDLE_TYPE"))
+ t << "\t\t\t" << writeSettings("explicitFileType", project->first("QMAKE_PBX_BUNDLE_TYPE")) + ";" << "\n";
+ } else if(project->isActiveConfig("app_bundle")) {
+ if(!project->isEmpty("QMAKE_APPLICATION_BUNDLE_NAME"))
+ targ = project->first("QMAKE_APPLICATION_BUNDLE_NAME");
+ targ += ".app";
+ t << "\t\t\t" << writeSettings("explicitFileType", "wrapper.application") << ";" << "\n";
+ } else {
+ t << "\t\t\t" << writeSettings("explicitFileType", "wrapper.executable") << ";" << "\n";
+ }
+ QString app = (!project->isEmpty("DESTDIR") ? project->first("DESTDIR") + project->first("QMAKE_ORIG_TARGET") :
+ qmake_getpwd()) + Option::dir_sep + targ;
+ t << "\t\t\t" << writeSettings("path", escapeFilePath(targ)) << ";" << "\n";
+ } else {
+ QString lib = project->first("QMAKE_ORIG_TARGET");
+ if(project->isActiveConfig("staticlib")) {
+ lib = project->first("TARGET");
+ } else if(!project->isActiveConfig("lib_bundle")) {
+ if(project->isActiveConfig("plugin"))
+ lib = project->first("TARGET");
+ else
+ lib = project->first("TARGET_");
+ }
+ int slsh = lib.lastIndexOf(Option::dir_sep);
+ if(slsh != -1)
+ lib = lib.right(lib.length() - slsh - 1);
+ if(project->isActiveConfig("bundle") && !project->isEmpty("QMAKE_BUNDLE_EXTENSION")) {
+ if(!project->isEmpty("QMAKE_BUNDLE_NAME"))
+ lib = project->first("QMAKE_BUNDLE_NAME");
+ lib += project->first("QMAKE_BUNDLE_EXTENSION");
+ if(!project->isEmpty("QMAKE_PBX_BUNDLE_TYPE"))
+ t << "\t\t\t" << writeSettings("explicitFileType", project->first("QMAKE_PBX_BUNDLE_TYPE")) << ";" << "\n";
+ } else if(!project->isActiveConfig("staticlib") && project->isActiveConfig("lib_bundle")) {
+ if(!project->isEmpty("QMAKE_FRAMEWORK_BUNDLE_NAME"))
+ lib = project->first("QMAKE_FRAMEWORK_BUNDLE_NAME");
+ lib += ".framework";
+ t << "\t\t\t" << writeSettings("explicitFileType", "wrapper.framework") << ";" << "\n";
+ } else {
+ t << "\t\t\t" << writeSettings("explicitFileType", "compiled.mach-o.dylib") << ";" << "\n";
+ }
+ t << "\t\t\t" << writeSettings("path", escapeFilePath(lib)) << ";" << "\n";
+ }
+ t << "\t\t\t" << writeSettings("refType", "3", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("sourceTree", "BUILT_PRODUCTS_DIR", SettingsNoQuote) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+ { //Products group
+ QString grp("Products"), key = keyFor(grp);
+ project->values("QMAKE_PBX_GROUPS").append(key);
+ t << "\t\t" << key << " = {" << "\n"
+ << "\t\t\t" << writeSettings("children", project->values("QMAKE_PBX_PRODUCTS"), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXGroup", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("name", "Products") << ";" << "\n"
+ << "\t\t\t" << writeSettings("refType", "4", SettingsNoQuote) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+ }
+ //TARGET
+ QString target_key = keyFor(pbx_dir + "QMAKE_PBX_TARGET");
+ project->values("QMAKE_PBX_TARGETS").append(target_key);
+ t << "\t\t" << target_key << " = {" << "\n"
+ << "\t\t\t" << writeSettings("buildPhases", project->values("QMAKE_PBX_PRESCRIPT_BUILDPHASES") + project->values("QMAKE_PBX_BUILDPHASES"),
+ SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << "buildSettings = {" << "\n";
+ QString cCompiler = project->first("QMAKE_CC");
+ if (!cCompiler.isEmpty()) {
+ t << "\t\t\t\t" << writeSettings("CC", fixForOutput(findProgram(cCompiler))) << ";" << "\n";
+ }
+ cCompiler = project->first("QMAKE_CXX");
+ if (!cCompiler.isEmpty()) {
+ t << "\t\t\t\t" << writeSettings("CPLUSPLUS", fixForOutput(findProgram(cCompiler))) << ";" << "\n";
+ }
+
+ t << "\t\t\t\t" << writeSettings("HEADER_SEARCH_PATHS", fixListForOutput("INCLUDEPATH") + QStringList(fixForOutput(specdir())), SettingsAsList, 5) << ";" << "\n"
+ << "\t\t\t\t" << writeSettings("LIBRARY_SEARCH_PATHS", fixListForOutput("QMAKE_PBX_LIBPATHS"), SettingsAsList, 5) << ";" << "\n"
+ << "\t\t\t\t" << writeSettings("OPTIMIZATION_CFLAGS", QStringList(), SettingsAsList, 5) << ";" << "\n";
+ {
+ QStringList cflags = fixListForOutput("QMAKE_CFLAGS");
+ const QStringList &prl_defines = project->values("PRL_EXPORT_DEFINES");
+ for(int i = 0; i < prl_defines.size(); ++i)
+ cflags += "-D" + prl_defines.at(i);
+ const QStringList &defines = project->values("DEFINES");
+ for(int i = 0; i < defines.size(); ++i)
+ cflags += "-D" + defines.at(i);
+ t << "\t\t\t\t" << writeSettings("OTHER_CFLAGS", cflags, SettingsAsList, 5) << ";" << "\n";
+ }
+ {
+ QStringList cxxflags = fixListForOutput("QMAKE_CXXFLAGS");
+ const QStringList &prl_defines = project->values("PRL_EXPORT_DEFINES");
+ for(int i = 0; i < prl_defines.size(); ++i)
+ cxxflags += "-D" + prl_defines.at(i);
+ const QStringList &defines = project->values("DEFINES");
+ for(int i = 0; i < defines.size(); ++i)
+ cxxflags += "-D" + defines.at(i);
+ t << "\t\t\t\t" << writeSettings("OTHER_CPLUSPLUSFLAGS", cxxflags, SettingsAsList, 5) << ";" << "\n";
+ }
+ t << "\t\t\t\t" << writeSettings("LEXFLAGS", fixListForOutput("QMAKE_LEXFLAGS")) << ";" << "\n"
+ << "\t\t\t\t" << writeSettings("YACCFLAGS", fixListForOutput("QMAKE_YACCFLAGS")) << ";" << "\n"
+ << "\t\t\t\t" << writeSettings("OTHER_REZFLAGS", QStringList()) << ";" << "\n"
+ << "\t\t\t\t" << writeSettings("SECTORDER_FLAGS", QStringList()) << ";" << "\n"
+ << "\t\t\t\t" << writeSettings("WARNING_CFLAGS", QStringList()) << ";" << "\n"
+ << "\t\t\t\t" << writeSettings("PREBINDING", QStringList((project->isEmpty("QMAKE_DO_PREBINDING") ? "NO" : "YES")), SettingsNoQuote) << ";" << "\n";
+ if(!project->isEmpty("PRECOMPILED_HEADER")) {
+ if(pbVersion >= 38) {
+ t << "\t\t\t\t" << writeSettings("GCC_PRECOMPILE_PREFIX_HEADER", "YES") << ";" << "\n"
+ << "\t\t\t\t" << writeSettings("GCC_PREFIX_HEADER", escapeFilePath(project->first("PRECOMPILED_HEADER"))) << ";" << "\n";
+ } else {
+ t << "\t\t\t\t" << writeSettings("PRECOMPILE_PREFIX_HEADER", "YES") << ";" << "\n"
+ << "\t\t\t\t" << writeSettings("PREFIX_HEADER", escapeFilePath(project->first("PRECOMPILED_HEADER"))) << ";" << "\n";
+ }
+ }
+ if((project->first("TEMPLATE") == "app" && project->isActiveConfig("app_bundle")) ||
+ (project->first("TEMPLATE") == "lib" && !project->isActiveConfig("staticlib") &&
+ project->isActiveConfig("lib_bundle"))) {
+ QString plist = fileFixify(project->first("QMAKE_INFO_PLIST"));
+ if(plist.isEmpty())
+ plist = specdir() + QDir::separator() + "Info.plist." + project->first("TEMPLATE");
+ if(exists(plist)) {
+ QFile plist_in_file(plist);
+ if(plist_in_file.open(QIODevice::ReadOnly)) {
+ QTextStream plist_in(&plist_in_file);
+ QString plist_in_text = plist_in.readAll();
+ plist_in_text = plist_in_text.replace("@ICON@",
+ (project->isEmpty("ICON") ? QString("") : project->first("ICON").section(Option::dir_sep, -1)));
+ if(project->first("TEMPLATE") == "app") {
+ plist_in_text = plist_in_text.replace("@EXECUTABLE@", project->first("QMAKE_ORIG_TARGET"));
+ } else {
+ plist_in_text = plist_in_text.replace("@LIBRARY@", project->first("QMAKE_ORIG_TARGET"));
+ plist_in_text = plist_in_text.replace("@SHORT_VERSION@", project->first("VER_MAJ") + "." +
+ project->first("VER_MIN"));
+ }
+ plist_in_text = plist_in_text.replace("@TYPEINFO@",
+ (project->isEmpty("QMAKE_PKGINFO_TYPEINFO") ? QString::fromLatin1("????") :
+ project->first("QMAKE_PKGINFO_TYPEINFO").left(4)));
+ QFile plist_out_file("Info.plist");
+ if(plist_out_file.open(QIODevice::WriteOnly | QIODevice::Text)) {
+ QTextStream plist_out(&plist_out_file);
+ plist_out << plist_in_text;
+ t << "\t\t\t\t" << writeSettings("INFOPLIST_FILE", "Info.plist") << ";" << "\n";
+ }
+ }
+ }
+ }
+#if 1
+ t << "\t\t\t\t" << writeSettings("BUILD_ROOT", escapeFilePath(qmake_getpwd())) << ";" << "\n";
+#endif
+ if(!project->isActiveConfig("staticlib")) {
+ t << "\t\t\t\t" << writeSettings("OTHER_LDFLAGS",
+ fixListForOutput("SUBLIBS")
+ + fixListForOutput("QMAKE_LFLAGS")
+ + fixListForOutput("QMAKE_LIBDIR_FLAGS")
+ + fixListForOutput("QMAKE_FRAMEWORKPATH_FLAGS")
+ + fixListForOutput("QMAKE_LIBS"),
+ SettingsAsList, 6) << ";" << "\n";
+ }
+ if(!project->isEmpty("DESTDIR")) {
+ QString dir = project->first("DESTDIR");
+ if (QDir::isRelativePath(dir))
+ dir.prepend(qmake_getpwd() + Option::dir_sep);
+ t << "\t\t\t\t" << writeSettings("INSTALL_DIR", dir) << ";" << "\n";
+ }
+ if (project->first("TEMPLATE") == "lib") {
+ t << "\t\t\t\t" << writeSettings("INSTALL_PATH", QStringList()) << ";" << "\n";
+ }
+ if(!project->isEmpty("VERSION") && project->first("VERSION") != "0.0.0") {
+ t << "\t\t\t\t" << writeSettings("DYLIB_CURRENT_VERSION", project->first("VER_MAJ")+"."+project->first("VER_MIN")+"."+project->first("VER_PAT")) << ";" << "\n";
+ if(project->isEmpty("COMPAT_VERSION"))
+ t << "\t\t\t\t" << writeSettings("DYLIB_COMPATIBILITY_VERSION", project->first("VER_MAJ")+"."+project->first("VER_MIN")) << ";" << "\n";
+ if(project->first("TEMPLATE") == "lib" && !project->isActiveConfig("staticlib") &&
+ project->isActiveConfig("lib_bundle"))
+ t << "\t\t\t\t" << writeSettings("FRAMEWORK_VERSION", project->first("QMAKE_FRAMEWORK_VERSION")) << ";" << "\n";
+ }
+ if(!project->isEmpty("COMPAT_FRAMEWORKPATH"))
+ t << "\t\t\t\t" << writeSettings("FRAMEWORK_SEARCH_PATHS", fixListForOutput("QMAKE_FRAMEWORKPATH"), SettingsAsList, 5) << ";" << "\n";
+ if(!project->isEmpty("COMPAT_VERSION"))
+ t << "\t\t\t\t" << writeSettings("DYLIB_COMPATIBILITY_VERSION", project->first("COMPAT_VERSION")) << ";" << "\n";
+ if(!project->isEmpty("QMAKE_MACOSX_DEPLOYMENT_TARGET"))
+ t << "\t\t\t\t" << writeSettings("MACOSX_DEPLOYMENT_TARGET", project->first("QMAKE_MACOSX_DEPLOYMENT_TARGET")) << ";" << "\n";
+ if(pbVersion >= 38) {
+ if(!project->isEmpty("OBJECTS_DIR"))
+ t << "\t\t\t\t" << writeSettings("OBJROOT", fixForOutput(project->first("OBJECTS_DIR"))) << ";" << "\n";
+ }
+#if 0
+ if(!project->isEmpty("DESTDIR"))
+ t << "\t\t\t\t" << writeSettings("SYMROOT", fixForOutput(project->first("DESTDIR"))) << ";" << "\n";
+ else
+ t << "\t\t\t\t" << writeSettings("SYMROOT", fixForOutput(qmake_getpwd())) << ";" << "\n";
+#endif
+ {
+ QStringList archs;
+ if(project->isActiveConfig("x86"))
+ archs += "i386";
+ if(project->isActiveConfig("ppc")) {
+ if(!archs.isEmpty())
+ archs += " ";
+ archs += "ppc";
+ }
+ if(project->isActiveConfig("ppc64")) {
+ if(!archs.isEmpty())
+ archs += " ";
+ archs += "ppc64";
+ }
+ if(project->isActiveConfig("x86_64")) {
+ if(!archs.isEmpty())
+ archs += " ";
+ archs += "x86_64";
+ }
+ if(!archs.isEmpty())
+ t << "\t\t\t\t" << writeSettings("ARCHS", archs) << ";" << "\n";
+
+ }
+ if(project->first("TEMPLATE") == "app") {
+ if(pbVersion < 38 && project->isActiveConfig("app_bundle"))
+ t << "\t\t\t\t" << writeSettings("WRAPPER_SUFFIX", "app") << ";" << "\n";
+ t << "\t\t\t\t" << writeSettings("PRODUCT_NAME", fixForOutput(project->first("QMAKE_ORIG_TARGET"))) << ";" << "\n";
+ } else {
+ if(!project->isActiveConfig("plugin") && project->isActiveConfig("staticlib")) {
+ t << "\t\t\t\t" << writeSettings("LIBRARY_STYLE", "STATIC") << ";" << "\n";
+ } else {
+ t << "\t\t\t\t" << writeSettings("LIBRARY_STYLE", "DYNAMIC") << ";" << "\n";
+ }
+ QString lib = project->first("QMAKE_ORIG_TARGET");
+ if(!project->isActiveConfig("lib_bundle") && !project->isActiveConfig("staticlib"))
+ lib.prepend("lib");
+ t << "\t\t\t\t" << writeSettings("PRODUCT_NAME", escapeFilePath(lib)) << ";" << "\n";
+ }
+ tmp = project->values("QMAKE_PBX_VARS");
+ for(int i = 0; i < tmp.count(); i++) {
+ QString var = tmp[i], val = qgetenv(var.toLatin1());
+ if(val.isEmpty() && var == "TB")
+ val = "/usr/bin/";
+ t << "\t\t\t\t" << writeSettings(var, escapeFilePath(val)) << ";" << "\n";
+ }
+ t << "\t\t\t" << "};" << "\n"
+ << "\t\t\t" << "conditionalBuildSettings = {" << "\n"
+ << "\t\t\t" << "};" << "\n"
+ << "\t\t\t" << writeSettings("dependencies", project->values("QMAKE_PBX_TARGET_DEPENDS"), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("productReference", keyFor(pbx_dir + "QMAKE_PBX_REFERENCE")) << ";" << "\n"
+ << "\t\t\t" << writeSettings("shouldUseHeadermap", "1", SettingsNoQuote) << ";" << "\n";
+ if(pbVersion >= 38)
+ t << "\t\t\t" << writeSettings("isa", "PBXNativeTarget", SettingsNoQuote) << ";" << "\n";
+ if(project->first("TEMPLATE") == "app") {
+ if(!project->isActiveConfig("app_bundle")) {
+ if(pbVersion >= 38) {
+ if(!project->isEmpty("QMAKE_PBX_PRODUCT_TYPE"))
+ t << "\t\t\t" << writeSettings("productType", project->first("QMAKE_PBX_PRODUCT_TYPE")) << ";" << "\n";
+ else
+ t << "\t\t\t" << writeSettings("productType", "com.apple.product-type.tool") << ";" << "\n";
+ } else {
+ t << "\t\t\t" << writeSettings("isa", "PBXToolTarget", SettingsNoQuote) << ";" << "\n";
+ }
+ } else {
+ if(pbVersion >= 38) {
+ if(!project->isEmpty("QMAKE_PBX_PRODUCT_TYPE"))
+ t << "\t\t\t" << writeSettings("productType", project->first("QMAKE_PBX_PRODUCT_TYPE")) << ";" << "\n";
+ else
+ t << "\t\t\t" << writeSettings("productType", "com.apple.product-type.application") << ";" << "\n";
+ } else {
+ t << "\t\t\t" << writeSettings("isa", "PBXApplicationTarget", SettingsNoQuote) << ";" << "\n";
+ }
+ t << "\t\t\t" << "productSettingsXML = \"";
+ bool read_plist = false;
+ if(exists("Info.plist")) {
+ QFile plist("Info.plist");
+ if (plist.open(QIODevice::ReadOnly)) {
+ read_plist = true;
+ QTextStream stream(&plist);
+ while(!stream.atEnd())
+ t << stream.readLine().replace('"', "\\\"") << endl;
+ }
+ }
+ if(!read_plist) {
+ t << "<?xml version="
+ << "\\\"1.0\\\" encoding=" << "\\\"UTF-8\\\"" << "?>" << "\n"
+ << "\t\t\t\t" << "<!DOCTYPE plist SYSTEM \\\"file://localhost/System/"
+ << "Library/DTDs/PropertyList.dtd\\\">" << "\n"
+ << "\t\t\t\t" << "<plist version=\\\"0.9\\\">" << "\n"
+ << "\t\t\t\t" << "<dict>" << "\n"
+ << "\t\t\t\t\t" << "<key>CFBundleDevelopmentRegion</key>" << "\n"
+ << "\t\t\t\t\t" << "<string>English</string>" << "\n"
+ << "\t\t\t\t\t" << "<key>CFBundleExecutable</key>" << "\n"
+ << "\t\t\t\t\t" << "<string>" << project->first("QMAKE_ORIG_TARGET") << "</string>" << "\n"
+ << "\t\t\t\t\t" << "<key>CFBundleIconFile</key>" << "\n"
+ << "\t\t\t\t\t" << "<string>" << var("ICON").section(Option::dir_sep, -1) << "</string>" << "\n"
+ << "\t\t\t\t\t" << "<key>CFBundleInfoDictionaryVersion</key>" << "\n"
+ << "\t\t\t\t\t" << "<string>6.0</string>" << "\n"
+ << "\t\t\t\t\t" << "<key>CFBundlePackageType</key>" << "\n"
+ << "\t\t\t\t\t" << "<string>APPL</string>" << "\n"
+ << "\t\t\t\t\t" << "<key>CFBundleSignature</key>" << "\n"
+ << "\t\t\t\t\t" << "<string>"
+ << (project->isEmpty("QMAKE_PKGINFO_TYPEINFO") ? QString::fromLatin1("????") :
+ project->first("QMAKE_PKGINFO_TYPEINFO").left(4)) << "</string>" << "\n"
+ << "\t\t\t\t\t" << "<key>CFBundleVersion</key>" << "\n"
+ << "\t\t\t\t\t" << "<string>0.1</string>" << "\n"
+ << "\t\t\t\t\t" << "<key>CSResourcesFileMapped</key>" << "\n"
+ << "\t\t\t\t\t" << "<true/>" << "\n"
+ << "\t\t\t\t" << "</dict>" << "\n"
+ << "\t\t\t\t" << "</plist>";
+ }
+ t << "\";" << "\n";
+ }
+ t << "\t\t\t" << writeSettings("name", escapeFilePath(project->first("QMAKE_ORIG_TARGET"))) << ";" << "\n"
+ << "\t\t\t" << writeSettings("productName", escapeFilePath(project->first("QMAKE_ORIG_TARGET"))) << ";" << "\n";
+ } else {
+ QString lib = project->first("QMAKE_ORIG_TARGET");
+ if(!project->isActiveConfig("lib_bundle") && !project->isActiveConfig("staticlib"))
+ lib.prepend("lib");
+ t << "\t\t\t" << writeSettings("name", escapeFilePath(lib)) << ";" << "\n"
+ << "\t\t\t" << writeSettings("productName", escapeFilePath(lib)) << ";" << "\n";
+ if(pbVersion >= 38) {
+ if(!project->isEmpty("QMAKE_PBX_PRODUCT_TYPE"))
+ t << "\t\t\t" << writeSettings("productType", project->first("QMAKE_PBX_PRODUCT_TYPE")) << ";" << "\n";
+ else if(project->isActiveConfig("staticlib"))
+ t << "\t\t\t" << writeSettings("productType", "com.apple.product-type.library.static") << ";" << "\n";
+ else if(project->isActiveConfig("lib_bundle"))
+ t << "\t\t\t" << writeSettings("productType", "com.apple.product-type.framework") << ";" << "\n";
+ else
+ t << "\t\t\t" << writeSettings("productType", "com.apple.product-type.library.dynamic") << ";" << "\n";
+ } else {
+ t << "\t\t\t" << writeSettings("isa", "PBXLibraryTarget", SettingsNoQuote) << ";" << "\n";
+ }
+ }
+ t << "\t\t\t" << writeSettings("startupPath", "<<ProjectDirectory>>") << ";" << "\n";
+ if(!project->isEmpty("DESTDIR"))
+ t << "\t\t\t" << writeSettings("productInstallPath", escapeFilePath(project->first("DESTDIR"))) << ";" << "\n";
+ t << "\t\t" << "};" << "\n";
+ //DEBUG/RELEASE
+ QString active_buildstyle;
+ for(int as_release = 0; as_release < 2; as_release++)
+ {
+ QMap<QString, QString> settings;
+ settings.insert("COPY_PHASE_STRIP", (as_release ? "YES" : "NO"));
+ settings.insert("GCC_GENERATE_DEBUGGING_SYMBOLS", as_release ? "NO" : "YES");
+ if(!as_release)
+ settings.insert("GCC_OPTIMIZATION_LEVEL", "0");
+ if(project->isActiveConfig("sdk") && !project->isEmpty("QMAKE_MAC_SDK"))
+ settings.insert("SDKROOT", project->first("QMAKE_MAC_SDK"));
+ {
+ const QStringList &l = project->values("QMAKE_MAC_XCODE_SETTINGS");
+ for(int i = 0; i < l.size(); ++i) {
+ QString name = l.at(i);
+ const QString value = project->values(name + QLatin1String(".value")).join(QString(Option::field_sep));
+ if(!project->isEmpty(name + QLatin1String(".name")))
+ name = project->values(name + QLatin1String(".name")).first();
+ settings.insert(name, value);
+ }
+ }
+
+ QString name;
+ if(pbVersion >= 42)
+ name = (as_release ? "Release" : "Debug");
+ else
+ name = (as_release ? "Deployment" : "Development");
+ if(pbVersion >= 42) {
+ QString key = keyFor("QMAKE_PBX_BUILDCONFIG_" + name);
+ project->values("QMAKE_PBX_BUILDCONFIGS").append(key);
+ t << "\t\t" << key << " = {" << "\n"
+ << "\t\t\t" << writeSettings("isa", "XCBuildConfiguration", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << "buildSettings = {" << "\n";
+ for(QMap<QString, QString>::Iterator set_it = settings.begin(); set_it != settings.end(); ++set_it)
+ t << "\t\t\t\t" << writeSettings(set_it.key(), set_it.value()) << ";\n";
+ t << "\t\t\t" << "};" << "\n"
+ << "\t\t\t" << writeSettings("name", name) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+ }
+
+ QString key = keyFor("QMAKE_PBX_BUILDSTYLE_" + name);
+ if(project->isActiveConfig("debug") != (bool)as_release) {
+ project->values("QMAKE_PBX_BUILDSTYLES").append(key);
+ active_buildstyle = name;
+ } else if(pbVersion >= 42) {
+ project->values("QMAKE_PBX_BUILDSTYLES").append(key);
+ }
+ t << "\t\t" << key << " = {" << "\n"
+ << "\t\t\t" << writeSettings("buildRules", QStringList(), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << "buildSettings = {" << "\n";
+ for(QMap<QString, QString>::Iterator set_it = settings.begin(); set_it != settings.end(); ++set_it)
+ t << "\t\t\t\t" << writeSettings(set_it.key(), set_it.value()) << ";" << "\n";
+ t << "\t\t\t" << "};" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXBuildStyle") << ";" << "\n"
+ << "\t\t\t" << writeSettings("name", name) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+ }
+ if(pbVersion >= 42) {
+ t << "\t\t" << keyFor("QMAKE_PBX_BUILDCONFIG_LIST") << " = {" << "\n"
+ << "\t\t\t" << writeSettings("isa", "XCConfigurationList", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("buildConfigurations", project->values("QMAKE_PBX_BUILDCONFIGS"), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("defaultConfigurationIsVisible", "0", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("defaultConfigurationIsName", active_buildstyle) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+ }
+ //ROOT
+ t << "\t\t" << keyFor("QMAKE_PBX_ROOT") << " = {" << "\n"
+ << "\t\t\t" << writeSettings("buildStyles", project->values("QMAKE_PBX_BUILDSTYLES"), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t\t" << writeSettings("hasScannedForEncodings", "1", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("isa", "PBXProject", SettingsNoQuote) << ";" << "\n"
+ << "\t\t\t" << writeSettings("mainGroup", keyFor("QMAKE_PBX_ROOT_GROUP")) << ";" << "\n";
+ if(pbVersion >= 42)
+ t << "\t\t\t" << writeSettings("buildConfigurationList", keyFor("QMAKE_PBX_BUILDCONFIG_LIST")) << ";" << "\n";
+ t << "\t\t\t" << writeSettings("projectDirPath", QStringList()) << ";" << "\n"
+ << "\t\t\t" << writeSettings("targets", project->values("QMAKE_PBX_TARGETS"), SettingsAsList, 4) << ";" << "\n"
+ << "\t\t" << "};" << "\n";
+
+ //FOOTER
+ t << "\t" << "};" << "\n"
+ << "\t" << writeSettings("rootObject", keyFor("QMAKE_PBX_ROOT")) << ";" << "\n"
+ << "}" << endl;
+
+ if(project->isActiveConfig("generate_pbxbuild_makefile")) {
+ QString mkwrap = fileFixify(pbx_dir + Option::dir_sep + ".." + Option::dir_sep + project->first("MAKEFILE"),
+ qmake_getpwd());
+ QFile mkwrapf(mkwrap);
+ if(mkwrapf.open(QIODevice::WriteOnly | QIODevice::Text)) {
+ writingUnixMakefileGenerator = true;
+ debug_msg(1, "pbuilder: Creating file: %s", mkwrap.toLatin1().constData());
+ QTextStream mkwrapt(&mkwrapf);
+ writeHeader(mkwrapt);
+ const char cleans[] = "preprocess_clean ";
+ mkwrapt << "#This is a makefile wrapper for PROJECT BUILDER\n"
+ << "all:" << "\n\t"
+ << "cd " << project->first("QMAKE_ORIG_TARGET") << projectSuffix() << "/ && " << pbxbuild() << "\n"
+ << "install: all" << "\n\t"
+ << "cd " << project->first("QMAKE_ORIG_TARGET") << projectSuffix() << "/ && " << pbxbuild() << " install\n"
+ << "distclean clean: preprocess_clean" << "\n\t"
+ << "cd " << project->first("QMAKE_ORIG_TARGET") << projectSuffix() << "/ && " << pbxbuild() << " clean" << "\n"
+ << (!did_preprocess ? cleans : "") << ":" << "\n";
+ if(did_preprocess)
+ mkwrapt << cleans << ":" << "\n\t"
+ << "make -f "
+ << pbx_dir << Option::dir_sep << "qt_preprocess.mak $@" << endl;
+ writingUnixMakefileGenerator = false;
+ }
+ }
+ return true;
+}
+
+QString
+ProjectBuilderMakefileGenerator::findProgram(const QString &prog)
+{
+ QString ret = prog;
+ if(QDir::isRelativePath(ret)) {
+ QStringList paths = QString(qgetenv("PATH")).split(':');
+ for(int i = 0; i < paths.size(); ++i) {
+ QString path = paths.at(i) + "/" + prog;
+ if(exists(path)) {
+ ret = path;
+ break;
+ }
+ }
+ }
+ return ret;
+}
+
+QString
+ProjectBuilderMakefileGenerator::fixForOutput(const QString &values)
+{
+ //get the environment variables references
+ QRegExp reg_var("\\$\\((.*)\\)");
+ for(int rep = 0; (rep = reg_var.indexIn(values, rep)) != -1;) {
+ if(project->values("QMAKE_PBX_VARS").indexOf(reg_var.cap(1)) == -1)
+ project->values("QMAKE_PBX_VARS").append(reg_var.cap(1));
+ rep += reg_var.matchedLength();
+ }
+ QString ret = values;
+ ret = ret.replace(QRegExp("\\\\ "), " "); //unescape spaces
+ ret = ret.replace(QRegExp("('|\\\\|\")"), "\\\\1"); //fix quotes
+ ret = ret.replace("\t", " "); //fix tabs
+ ret = ret.replace(QRegExp(" "), "\\ "); //escape spaces
+ return ret;
+}
+
+QStringList
+ProjectBuilderMakefileGenerator::fixListForOutput(const QString &where)
+{
+ QStringList ret;
+ const QStringList &l = project->values(where);
+ for(int i = 0; i < l.count(); i++)
+ ret += fixForOutput(l[i]);
+ return ret;
+}
+
+QString
+ProjectBuilderMakefileGenerator::keyFor(const QString &block)
+{
+#if 1 //This make this code much easier to debug..
+ if(project->isActiveConfig("no_pb_munge_key"))
+ return block;
+#endif
+ QString ret;
+ if(!keys.contains(block)) {
+ ret = qtMD5(block.toUtf8()).left(24).toUpper();
+ keys.insert(block, ret);
+ } else {
+ ret = keys[block];
+ }
+ return ret;
+}
+
+bool
+ProjectBuilderMakefileGenerator::openOutput(QFile &file, const QString &build) const
+{
+ if(QDir::isRelativePath(file.fileName()))
+ file.setFileName(Option::output_dir + "/" + file.fileName()); //pwd when qmake was run
+ QFileInfo fi(fileInfo(file.fileName()));
+ if(fi.suffix() != "pbxproj" || file.fileName().isEmpty()) {
+ QString output = file.fileName();
+ if(fi.isDir())
+ output += QDir::separator();
+ if(!output.endsWith(projectSuffix())) {
+ if(file.fileName().isEmpty() || fi.isDir()) {
+ if(project->first("TEMPLATE") == "subdirs" || project->isEmpty("QMAKE_ORIG_TARGET"))
+ output += fileInfo(project->projectFile()).baseName();
+ else
+ output += project->first("QMAKE_ORIG_TARGET");
+ }
+ output += projectSuffix() + QDir::separator();
+ } else if(output[(int)output.length() - 1] != QDir::separator()) {
+ output += QDir::separator();
+ }
+ output += QString("project.pbxproj");
+ output = unescapeFilePath(output);
+ file.setFileName(output);
+ }
+ bool ret = UnixMakefileGenerator::openOutput(file, build);
+ ((ProjectBuilderMakefileGenerator*)this)->pbx_dir = Option::output_dir.section(Option::dir_sep, 0, -1);
+ Option::output_dir = pbx_dir.section(Option::dir_sep, 0, -2);
+ return ret;
+}
+
+/* This function is such a hack it is almost pointless, but it
+ eliminates the warning message from ProjectBuilder that the project
+ file is for an older version. I guess this could be used someday if
+ the format of the output is dependant upon the version of
+ ProjectBuilder as well.
+*/
+int
+ProjectBuilderMakefileGenerator::pbuilderVersion() const
+{
+ QString ret;
+ if(!project->isEmpty("QMAKE_PBUILDER_VERSION")) {
+ ret = project->first("QMAKE_PBUILDER_VERSION");
+ } else {
+ QString version, version_plist = project->first("QMAKE_PBUILDER_VERSION_PLIST");
+ if(version_plist.isEmpty()) {
+#ifdef Q_OS_DARWIN
+ ret = QLatin1String("34");
+ QCFType<CFURLRef> cfurl;
+ OSStatus err = LSFindApplicationForInfo(0, CFSTR("com.apple.Xcode"), 0, 0, &cfurl);
+ if (err == noErr) {
+ QCFType<CFBundleRef> bundle = CFBundleCreate(0, cfurl);
+ if (bundle) {
+ CFStringRef str = CFStringRef(CFBundleGetValueForInfoDictionaryKey(bundle,
+ CFSTR("CFBundleShortVersionString")));
+ if (str) {
+ QStringList versions = QCFString::toQString(str).split(QLatin1Char('.'));
+ int versionMajor = versions.at(0).toInt();
+ int versionMinor = versions.at(1).toInt();
+ if (versionMajor >= 2) {
+ ret = QLatin1String("42");
+ } else if (versionMajor == 1 && versionMinor >= 5) {
+ ret = QLatin1String("39");
+ }
+ }
+ }
+ }
+#else
+ if(exists("/Developer/Applications/Xcode.app/Contents/version.plist"))
+ version_plist = "/Developer/Applications/Xcode.app/Contents/version.plist";
+ else
+ version_plist = "/Developer/Applications/Project Builder.app/Contents/version.plist";
+#endif
+ } else {
+ version_plist = version_plist.replace(QRegExp("\""), "");
+ }
+ if (ret.isEmpty()) {
+ QFile version_file(version_plist);
+ if (version_file.open(QIODevice::ReadOnly)) {
+ debug_msg(1, "pbuilder: version.plist: Reading file: %s", version_plist.toLatin1().constData());
+ QTextStream plist(&version_file);
+
+ bool in_dict = false;
+ QString current_key;
+ QRegExp keyreg("^<key>(.*)</key>$"), stringreg("^<string>(.*)</string>$");
+ while(!plist.atEnd()) {
+ QString line = plist.readLine().trimmed();
+ if(line == "<dict>")
+ in_dict = true;
+ else if(line == "</dict>")
+ in_dict = false;
+ else if(in_dict) {
+ if(keyreg.exactMatch(line))
+ current_key = keyreg.cap(1);
+ else if(current_key == "CFBundleShortVersionString" && stringreg.exactMatch(line))
+ version = stringreg.cap(1);
+ }
+ }
+ plist.flush();
+ version_file.close();
+ } else {
+ debug_msg(1, "pbuilder: version.plist: Failure to open %s", version_plist.toLatin1().constData());
+ }
+ if(version.isEmpty() && version_plist.contains("Xcode")) {
+ ret = "39";
+ } else {
+ int versionMajor = version.left(1).toInt();
+ if(versionMajor >= 2)
+ ret = "42";
+ else if(version == "1.5")
+ ret = "39";
+ else if(version == "1.1")
+ ret = "34";
+ }
+ }
+ }
+
+ if(!ret.isEmpty()) {
+ bool ok;
+ int int_ret = ret.toInt(&ok);
+ if(ok) {
+ debug_msg(1, "pbuilder: version.plist: Got version: %d", int_ret);
+ return int_ret;
+ }
+ }
+ debug_msg(1, "pbuilder: version.plist: Fallback to default version");
+ return 42; //my fallback
+}
+
+int
+ProjectBuilderMakefileGenerator::reftypeForFile(const QString &where)
+{
+ int ret = 0; //absolute is the default..
+ if(QDir::isRelativePath(unescapeFilePath(where)))
+ ret = 4; //relative
+ return ret;
+}
+
+QString
+ProjectBuilderMakefileGenerator::projectSuffix() const
+{
+ const int pbVersion = pbuilderVersion();
+ if(pbVersion >= 42)
+ return ".xcodeproj";
+ else if(pbVersion >= 38)
+ return ".xcode";
+ return ".pbproj";
+}
+
+QString
+ProjectBuilderMakefileGenerator::pbxbuild()
+{
+ if(exists("/usr/bin/pbbuild"))
+ return "pbbuild";
+ if(exists("/usr/bin/xcodebuild"))
+ return "xcodebuild";
+ return (pbuilderVersion() >= 38 ? "xcodebuild" : "pbxbuild");
+}
+
+QString
+ProjectBuilderMakefileGenerator::escapeFilePath(const QString &path) const
+{
+#if 1
+ //in the middle of generating a Makefile!
+ if(writingUnixMakefileGenerator)
+ return UnixMakefileGenerator::escapeFilePath(path);
+
+ //generating stuff for the xml file!
+ QString ret = path;
+ if(!ret.isEmpty()) {
+ ret = unescapeFilePath(ret);
+ debug_msg(2, "EscapeFilePath: %s -> %s", path.toLatin1().constData(), ret.toLatin1().constData());
+ }
+ return ret;
+#else
+ return UnixMakefileGenerator::escapeFilePath(path);
+#endif
+}
+
+QString
+ProjectBuilderMakefileGenerator::writeSettings(QString var, QStringList vals, int flags, int indent_level)
+{
+ QString ret;
+ const QString quote = (flags & SettingsNoQuote) ? "" : "\"";
+ const QString escape_quote = quote.isEmpty() ? "" : "\\" + quote;
+ QString newline = "\n";
+ for(int i = 0; i < indent_level; ++i)
+ newline += "\t";
+ if(flags & SettingsAsList) {
+ ret += var + " = (" + newline;
+ for(int i = 0, count = 0; i < vals.size(); ++i) {
+ QString val = vals.at(i);
+ if(!val.isEmpty()) {
+ if(count++ > 0)
+ ret += "," + newline;
+ ret += quote + val.replace(quote, escape_quote) + quote;
+ }
+ }
+ ret += ")";
+ } else {
+ ret += var + " = " + quote;
+ for(int i = 0; i < vals.size(); ++i) {
+ QString val = vals.at(i);
+// if(val.isEmpty())
+// val = quote + quote;
+ if(i)
+ ret += " ";
+ ret += val;
+ }
+ ret += quote;
+ }
+ return ret;
+}
+
+QT_END_NAMESPACE
diff --git a/qmake/generators/mac/pbuilder_pbx.h b/qmake/generators/mac/pbuilder_pbx.h
new file mode 100644
index 0000000..c9f5ae9
--- /dev/null
+++ b/qmake/generators/mac/pbuilder_pbx.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PBUILDER_PBX_H
+#define PBUILDER_PBX_H
+
+#include "unixmake.h"
+
+QT_BEGIN_NAMESPACE
+
+class ProjectBuilderMakefileGenerator : public UnixMakefileGenerator
+{
+ bool writingUnixMakefileGenerator;
+ QString pbx_dir;
+ int pbuilderVersion() const;
+ bool writeSubDirs(QTextStream &);
+ bool writeMakeParts(QTextStream &);
+ bool writeMakefile(QTextStream &);
+
+ QString pbxbuild();
+ QMap<QString, QString> keys;
+ QString keyFor(const QString &file);
+ QString findProgram(const QString &prog);
+ QString fixForOutput(const QString &file);
+ QStringList fixListForOutput(const QString &where);
+ int reftypeForFile(const QString &where);
+ QString projectSuffix() const;
+ enum { SettingsAsList=0x01, SettingsNoQuote=0x02 };
+ inline QString writeSettings(QString var, QString val, int flags=0, int indent_level=0)
+ { Q_UNUSED(indent_level); return writeSettings(var, QStringList(val), flags); }
+ QString writeSettings(QString var, QStringList vals, int flags=0, int indent_level=0);
+
+public:
+ ProjectBuilderMakefileGenerator();
+ ~ProjectBuilderMakefileGenerator();
+
+ virtual bool supportsMetaBuild() { return false; }
+ virtual bool openOutput(QFile &, const QString &) const;
+protected:
+ virtual QString escapeFilePath(const QString &path) const;
+ bool doPrecompiledHeaders() const { return false; }
+ virtual bool doDepends() const { return false; } //never necesary
+};
+
+inline ProjectBuilderMakefileGenerator::~ProjectBuilderMakefileGenerator()
+{ }
+
+QT_END_NAMESPACE
+
+#endif // PBUILDER_PBX_H
diff --git a/qmake/generators/makefile.cpp b/qmake/generators/makefile.cpp
new file mode 100644
index 0000000..24e030e
--- /dev/null
+++ b/qmake/generators/makefile.cpp
@@ -0,0 +1,3023 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "makefile.h"
+#include "option.h"
+#include "cachekeys.h"
+#include "meta.h"
+#include <qdir.h>
+#include <qfile.h>
+#include <qtextstream.h>
+#include <qregexp.h>
+#include <qhash.h>
+#include <qdebug.h>
+#include <qbuffer.h>
+#include <qsettings.h>
+#include <qdatetime.h>
+#if defined(Q_OS_UNIX)
+#include <unistd.h>
+#else
+#include <io.h>
+#endif
+#include <qdebug.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+QT_BEGIN_NAMESPACE
+
+// Well, Windows doesn't have this, so here's the macro
+#ifndef S_ISDIR
+# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#endif
+
+bool MakefileGenerator::canExecute(const QStringList &cmdline, int *a) const
+{
+ int argv0 = -1;
+ for(int i = 0; i < cmdline.count(); ++i) {
+ if(!cmdline.at(i).contains('=')) {
+ argv0 = i;
+ break;
+ }
+ }
+ if(a)
+ *a = argv0;
+ if(argv0 != -1) {
+ const QString c = Option::fixPathToLocalOS(cmdline.at(argv0), true);
+ if(exists(c))
+ return true;
+ }
+ return false;
+}
+
+QString MakefileGenerator::mkdir_p_asstring(const QString &dir, bool escape) const
+{
+ QString ret = "@$(CHK_DIR_EXISTS) ";
+ if(escape)
+ ret += escapeFilePath(dir);
+ else
+ ret += dir;
+ ret += " ";
+ if(isWindowsShell())
+ ret += "$(MKDIR)";
+ else
+ ret += "|| $(MKDIR)";
+ ret += " ";
+ if(escape)
+ ret += escapeFilePath(dir);
+ else
+ ret += dir;
+ ret += " ";
+ return ret;
+}
+
+bool MakefileGenerator::mkdir(const QString &in_path) const
+{
+ QString path = Option::fixPathToLocalOS(in_path);
+ if(QFile::exists(path))
+ return true;
+
+ QDir d;
+ if(path.startsWith(QDir::separator())) {
+ d.cd(QString(QDir::separator()));
+ path = path.right(path.length() - 1);
+ }
+ bool ret = true;
+#ifdef Q_OS_WIN
+ bool driveExists = true;
+ if(!QDir::isRelativePath(path)) {
+ if(QFile::exists(path.left(3))) {
+ d.cd(path.left(3));
+ path = path.right(path.length() - 3);
+ } else {
+ warn_msg(WarnLogic, "Cannot access drive '%s' (%s)",
+ path.left(3).toLatin1().data(), path.toLatin1().data());
+ driveExists = false;
+ }
+ }
+ if(driveExists)
+#endif
+ {
+ QStringList subs = path.split(QDir::separator());
+ for(QStringList::Iterator subit = subs.begin(); subit != subs.end(); ++subit) {
+ if(!d.cd(*subit)) {
+ d.mkdir((*subit));
+ if(d.exists((*subit))) {
+ d.cd((*subit));
+ } else {
+ ret = false;
+ break;
+ }
+ }
+ }
+ }
+ return ret;
+}
+
+// ** base makefile generator
+MakefileGenerator::MakefileGenerator() :
+ init_opath_already(false), init_already(false), no_io(false), project(0)
+{
+}
+
+
+void
+MakefileGenerator::verifyCompilers()
+{
+ QMap<QString, QStringList> &v = project->variables();
+ QStringList &quc = v["QMAKE_EXTRA_COMPILERS"];
+ for(int i = 0; i < quc.size(); ) {
+ bool error = false;
+ QString comp = quc.at(i);
+ if(v[comp + ".output"].isEmpty()) {
+ if(!v[comp + ".output_function"].isEmpty()) {
+ v[comp + ".output"].append("${QMAKE_FUNC_FILE_IN_" + v[comp + ".output_function"].first() + "}");
+ } else {
+ error = true;
+ warn_msg(WarnLogic, "Compiler: %s: No output file specified", comp.toLatin1().constData());
+ }
+ } else if(v[comp + ".input"].isEmpty()) {
+ error = true;
+ warn_msg(WarnLogic, "Compiler: %s: No input variable specified", comp.toLatin1().constData());
+ }
+ if(error)
+ quc.removeAt(i);
+ else
+ ++i;
+ }
+}
+
+void
+MakefileGenerator::initOutPaths()
+{
+ if(init_opath_already)
+ return;
+ verifyCompilers();
+ init_opath_already = true;
+ QMap<QString, QStringList> &v = project->variables();
+ //for shadow builds
+ if(!v.contains("QMAKE_ABSOLUTE_SOURCE_PATH")) {
+ if(Option::mkfile::do_cache && !Option::mkfile::cachefile.isEmpty() &&
+ v.contains("QMAKE_ABSOLUTE_SOURCE_ROOT")) {
+ QString root = v["QMAKE_ABSOLUTE_SOURCE_ROOT"].first();
+ root = Option::fixPathToTargetOS(root);
+ if(!root.isEmpty()) {
+ QFileInfo fi = fileInfo(Option::mkfile::cachefile);
+ if(!fi.makeAbsolute()) {
+ QString cache_r = fi.path(), pwd = Option::output_dir;
+ if(pwd.startsWith(cache_r) && !pwd.startsWith(root)) {
+ pwd = Option::fixPathToTargetOS(root + pwd.mid(cache_r.length()));
+ if(exists(pwd))
+ v.insert("QMAKE_ABSOLUTE_SOURCE_PATH", QStringList(pwd));
+ }
+ }
+ }
+ }
+ }
+ if(!v["QMAKE_ABSOLUTE_SOURCE_PATH"].isEmpty()) {
+ QString &asp = v["QMAKE_ABSOLUTE_SOURCE_PATH"].first();
+ asp = Option::fixPathToTargetOS(asp);
+ if(asp.isEmpty() || asp == Option::output_dir) //if they're the same, why bother?
+ v["QMAKE_ABSOLUTE_SOURCE_PATH"].clear();
+ }
+
+ QString currentDir = qmake_getpwd(); //just to go back to
+
+ //some builtin directories
+ if(project->isEmpty("PRECOMPILED_DIR") && !project->isEmpty("OBJECTS_DIR"))
+ v["PRECOMPILED_DIR"] = v["OBJECTS_DIR"];
+ QString dirs[] = { QString("OBJECTS_DIR"), QString("DESTDIR"), QString("QMAKE_PKGCONFIG_DESTDIR"),
+ QString("SUBLIBS_DIR"), QString("DLLDESTDIR"), QString("QMAKE_LIBTOOL_DESTDIR"),
+ QString("PRECOMPILED_DIR"), QString() };
+ for(int x = 0; !dirs[x].isEmpty(); x++) {
+ if(v[dirs[x]].isEmpty())
+ continue;
+ const QString orig_path = v[dirs[x]].first();
+
+ QString &pathRef = v[dirs[x]].first();
+ pathRef = fileFixify(pathRef, Option::output_dir, Option::output_dir);
+
+#ifdef Q_OS_WIN
+ // We don't want to add a separator for DLLDESTDIR on Windows (###why?)
+ if(!(dirs[x] == "DLLDESTDIR"))
+#endif
+ {
+ if(pathRef.right(Option::dir_sep.length()) != Option::dir_sep)
+ pathRef += Option::dir_sep;
+ }
+
+ if(noIO())
+ continue;
+
+ QString path = project->first(dirs[x]); //not to be changed any further
+ path = fileFixify(path, currentDir, Option::output_dir);
+ debug_msg(3, "Fixed output_dir %s (%s) into %s", dirs[x].toLatin1().constData(),
+ orig_path.toLatin1().constData(), path.toLatin1().constData());
+ if(!mkdir(path))
+ warn_msg(WarnLogic, "%s: Cannot access directory '%s'", dirs[x].toLatin1().constData(),
+ path.toLatin1().constData());
+ }
+
+ //out paths from the extra compilers
+ const QStringList &quc = project->values("QMAKE_EXTRA_COMPILERS");
+ for(QStringList::ConstIterator it = quc.begin(); it != quc.end(); ++it) {
+ QString tmp_out = project->values((*it) + ".output").first();
+ if(tmp_out.isEmpty())
+ continue;
+ const QStringList &tmp = project->values((*it) + ".input");
+ for(QStringList::ConstIterator it2 = tmp.begin(); it2 != tmp.end(); ++it2) {
+ QStringList &inputs = project->values((*it2));
+ for(QStringList::Iterator input = inputs.begin(); input != inputs.end(); ++input) {
+ (*input) = fileFixify((*input), Option::output_dir, Option::output_dir);
+ QString path = unescapeFilePath(replaceExtraCompilerVariables(tmp_out, (*input), QString()));
+ path = Option::fixPathToTargetOS(path);
+ int slash = path.lastIndexOf(Option::dir_sep);
+ if(slash != -1) {
+ path = path.left(slash);
+ if(path != "." &&
+ !mkdir(fileFixify(path, qmake_getpwd(), Option::output_dir)))
+ warn_msg(WarnLogic, "%s: Cannot access directory '%s'",
+ (*it).toLatin1().constData(), path.toLatin1().constData());
+ }
+ }
+ }
+ }
+
+ if(!v["DESTDIR"].isEmpty()) {
+ QDir d(v["DESTDIR"].first());
+ if(Option::fixPathToLocalOS(d.absolutePath()) == Option::fixPathToLocalOS(Option::output_dir))
+ v.remove("DESTDIR");
+ }
+ QDir::current().cd(currentDir);
+}
+
+QMakeProject
+*MakefileGenerator::projectFile() const
+{
+ return project;
+}
+
+void
+MakefileGenerator::setProjectFile(QMakeProject *p)
+{
+ if(project)
+ return;
+ project = p;
+ init();
+ usePlatformDir();
+ findLibraries();
+ if(Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE &&
+ project->isActiveConfig("link_prl")) //load up prl's'
+ processPrlFiles();
+}
+
+QStringList
+MakefileGenerator::findFilesInVPATH(QStringList l, uchar flags, const QString &vpath_var)
+{
+ QStringList vpath;
+ QMap<QString, QStringList> &v = project->variables();
+ for(int val_it = 0; val_it < l.count(); ) {
+ bool remove_file = false;
+ QString &val = l[val_it];
+ if(!val.isEmpty()) {
+ QString file = fixEnvVariables(val);
+ if(!(flags & VPATH_NoFixify))
+ file = fileFixify(file, qmake_getpwd(), Option::output_dir);
+ if (file.at(0) == '\"' && file.at(file.length() - 1) == '\"')
+ file = file.mid(1, file.length() - 2);
+
+ if(exists(file)) {
+ ++val_it;
+ continue;
+ }
+ bool found = false;
+ if(QDir::isRelativePath(val)) {
+ if(vpath.isEmpty()) {
+ if(!vpath_var.isEmpty())
+ vpath = v[vpath_var];
+ vpath += v["VPATH"] + v["QMAKE_ABSOLUTE_SOURCE_PATH"] + v["DEPENDPATH"];
+ if(Option::output_dir != qmake_getpwd())
+ vpath += Option::output_dir;
+ }
+ for(QStringList::Iterator vpath_it = vpath.begin();
+ vpath_it != vpath.end(); ++vpath_it) {
+ QString real_dir = Option::fixPathToLocalOS((*vpath_it));
+ if(exists(real_dir + QDir::separator() + val)) {
+ QString dir = (*vpath_it);
+ if(dir.right(Option::dir_sep.length()) != Option::dir_sep)
+ dir += Option::dir_sep;
+ val = dir + val;
+ if(!(flags & VPATH_NoFixify))
+ val = fileFixify(val);
+ found = true;
+ debug_msg(1, "Found file through vpath %s -> %s",
+ file.toLatin1().constData(), val.toLatin1().constData());
+ break;
+ }
+ }
+ }
+ if(!found) {
+ QString dir, regex = val, real_dir;
+ if(regex.lastIndexOf(Option::dir_sep) != -1) {
+ dir = regex.left(regex.lastIndexOf(Option::dir_sep) + 1);
+ real_dir = dir;
+ if(!(flags & VPATH_NoFixify))
+ real_dir = fileFixify(real_dir, qmake_getpwd(), Option::output_dir);
+ regex = regex.right(regex.length() - dir.length());
+ }
+ if(real_dir.isEmpty() || exists(real_dir)) {
+ QStringList files = QDir(real_dir).entryList(QStringList(regex));
+ if(files.isEmpty()) {
+ debug_msg(1, "%s:%d Failure to find %s in vpath (%s)",
+ __FILE__, __LINE__,
+ val.toLatin1().constData(), vpath.join("::").toLatin1().constData());
+ if(flags & VPATH_RemoveMissingFiles)
+ remove_file = true;
+ else if(flags & VPATH_WarnMissingFiles)
+ warn_msg(WarnLogic, "Failure to find: %s", val.toLatin1().constData());
+ } else {
+ l.removeAt(val_it);
+ QString a;
+ for(int i = (int)files.count()-1; i >= 0; i--) {
+ if(files[i] == "." || files[i] == "..")
+ continue;
+ a = dir + files[i];
+ if(!(flags & VPATH_NoFixify))
+ a = fileFixify(a);
+ l.insert(val_it, a);
+ }
+ }
+ } else {
+ debug_msg(1, "%s:%d Cannot match %s%c%s, as %s does not exist.",
+ __FILE__, __LINE__, real_dir.toLatin1().constData(),
+ QDir::separator().toLatin1(),
+ regex.toLatin1().constData(), real_dir.toLatin1().constData());
+ if(flags & VPATH_RemoveMissingFiles)
+ remove_file = true;
+ else if(flags & VPATH_WarnMissingFiles)
+ warn_msg(WarnLogic, "Failure to find: %s", val.toLatin1().constData());
+ }
+ }
+ }
+ if(remove_file)
+ l.removeAt(val_it);
+ else
+ ++val_it;
+ }
+ return l;
+}
+
+void
+MakefileGenerator::initCompiler(const MakefileGenerator::Compiler &comp)
+{
+ QMap<QString, QStringList> &v = project->variables();
+ QStringList &l = v[comp.variable_in];
+ // find all the relevant file inputs
+ if(!init_compiler_already.contains(comp.variable_in)) {
+ init_compiler_already.insert(comp.variable_in, true);
+ if(!noIO())
+ l = findFilesInVPATH(l, (comp.flags & Compiler::CompilerRemoveNoExist) ?
+ VPATH_RemoveMissingFiles : VPATH_WarnMissingFiles, "VPATH_" + comp.variable_in);
+ }
+}
+
+void
+MakefileGenerator::init()
+{
+ initOutPaths();
+ if(init_already)
+ return;
+ verifyCompilers();
+ init_already = true;
+
+ QMap<QString, QStringList> &v = project->variables();
+ QStringList &quc = v["QMAKE_EXTRA_COMPILERS"];
+
+ //make sure the COMPILERS are in the correct input/output chain order
+ for(int comp_out = 0, jump_count = 0; comp_out < quc.size(); ++comp_out) {
+ continue_compiler_chain:
+ if(jump_count > quc.size()) //just to avoid an infinite loop here
+ break;
+ if(project->variables().contains(quc.at(comp_out) + ".variable_out")) {
+ const QStringList &outputs = project->variables().value(quc.at(comp_out) + ".variable_out");
+ for(int out = 0; out < outputs.size(); ++out) {
+ for(int comp_in = 0; comp_in < quc.size(); ++comp_in) {
+ if(comp_in == comp_out)
+ continue;
+ if(project->variables().contains(quc.at(comp_in) + ".input")) {
+ const QStringList &inputs = project->variables().value(quc.at(comp_in) + ".input");
+ for(int in = 0; in < inputs.size(); ++in) {
+ if(inputs.at(in) == outputs.at(out) && comp_out > comp_in) {
+ ++jump_count;
+ //move comp_out to comp_in and continue the compiler chain
+ quc.move(comp_out, comp_in);
+ comp_out = comp_in;
+ goto continue_compiler_chain;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if(!project->isEmpty("QMAKE_SUBSTITUTES")) {
+ const QStringList &subs = v["QMAKE_SUBSTITUTES"];
+ for(int i = 0; i < subs.size(); ++i) {
+ if(!subs.at(i).endsWith(".in")) {
+ warn_msg(WarnLogic, "Substitute '%s' does not end with '.in'",
+ subs.at(i).toLatin1().constData());
+ continue;
+ }
+ QFile in(fileFixify(subs.at(i))), out(fileInfo(subs.at(i)).fileName());
+ if(out.fileName().endsWith(".in"))
+ out.setFileName(out.fileName().left(out.fileName().length()-3));
+ if(in.open(QFile::ReadOnly)) {
+ QString contents;
+ QStack<int> state;
+ enum { IN_CONDITION, MET_CONDITION, PENDING_CONDITION };
+ for(int count = 1; !in.atEnd(); ++count) {
+ QString line = QString::fromUtf8(in.readLine());
+ if(line.startsWith("!!IF ")) {
+ if(state.isEmpty() || state.top() == IN_CONDITION) {
+ QString test = line.mid(5, line.length()-(5+1));
+ if(project->test(test))
+ state.push(IN_CONDITION);
+ else
+ state.push(PENDING_CONDITION);
+ } else {
+ state.push(MET_CONDITION);
+ }
+ } else if(line.startsWith("!!ELIF ")) {
+ if(state.isEmpty()) {
+ warn_msg(WarnLogic, "(%s:%d): Unexpected else condition",
+ in.fileName().toLatin1().constData(), count);
+ } else if(state.top() == PENDING_CONDITION) {
+ QString test = line.mid(7, line.length()-(7+1));
+ if(project->test(test)) {
+ state.pop();
+ state.push(IN_CONDITION);
+ }
+ } else if(state.top() == IN_CONDITION) {
+ state.pop();
+ state.push(MET_CONDITION);
+ }
+ } else if(line.startsWith("!!ELSE")) {
+ if(state.isEmpty()) {
+ warn_msg(WarnLogic, "(%s:%d): Unexpected else condition",
+ in.fileName().toLatin1().constData(), count);
+ } else if(state.top() == PENDING_CONDITION) {
+ state.pop();
+ state.push(IN_CONDITION);
+ } else if(state.top() == IN_CONDITION) {
+ state.pop();
+ state.push(MET_CONDITION);
+ }
+ } else if(line.startsWith("!!ENDIF")) {
+ if(state.isEmpty())
+ warn_msg(WarnLogic, "(%s:%d): Unexpected endif",
+ in.fileName().toLatin1().constData(), count);
+ else
+ state.pop();
+ } else if(state.isEmpty() || state.top() == IN_CONDITION) {
+ contents += project->expand(line).join(QString(Option::field_sep));
+ }
+ }
+ if(out.exists() && out.open(QFile::ReadOnly)) {
+ QString old = QString::fromUtf8(out.readAll());
+ if(contents == old) {
+ v["QMAKE_INTERNAL_INCLUDED_FILES"].append(subs.at(i));
+ continue;
+ }
+ out.close();
+ if(!out.remove()) {
+ warn_msg(WarnLogic, "Cannot clear substitute '%s'",
+ out.fileName().toLatin1().constData());
+ continue;
+ }
+ }
+ if(out.open(QFile::WriteOnly)) {
+ v["QMAKE_INTERNAL_INCLUDED_FILES"].append(subs.at(i));
+ out.write(contents.toUtf8());
+ } else {
+ warn_msg(WarnLogic, "Cannot open substitute for output '%s'",
+ out.fileName().toLatin1().constData());
+ }
+ } else {
+ warn_msg(WarnLogic, "Cannot open substitute for input '%s'",
+ in.fileName().toLatin1().constData());
+ }
+ }
+ }
+
+ int x;
+
+ //build up a list of compilers
+ QList<Compiler> compilers;
+ {
+ const char *builtins[] = { "OBJECTS", "SOURCES", "PRECOMPILED_HEADER", 0 };
+ for(x = 0; builtins[x]; ++x) {
+ Compiler compiler;
+ compiler.variable_in = builtins[x];
+ compiler.flags = Compiler::CompilerBuiltin;
+ compiler.type = QMakeSourceFileInfo::TYPE_C;
+ if(!strcmp(builtins[x], "OBJECTS"))
+ compiler.flags |= Compiler::CompilerNoCheckDeps;
+ compilers.append(compiler);
+ }
+ for(QStringList::ConstIterator it = quc.begin(); it != quc.end(); ++it) {
+ const QStringList &inputs = v[(*it) + ".input"];
+ for(x = 0; x < inputs.size(); ++x) {
+ Compiler compiler;
+ compiler.variable_in = inputs.at(x);
+ compiler.flags = Compiler::CompilerNoFlags;
+ if(v[(*it) + ".CONFIG"].indexOf("ignore_no_exist") != -1)
+ compiler.flags |= Compiler::CompilerRemoveNoExist;
+ if(v[(*it) + ".CONFIG"].indexOf("no_dependencies") != -1)
+ compiler.flags |= Compiler::CompilerNoCheckDeps;
+
+ QString dep_type;
+ if(!project->isEmpty((*it) + ".dependency_type"))
+ dep_type = project->first((*it) + ".dependency_type");
+ if (dep_type.isEmpty())
+ compiler.type = QMakeSourceFileInfo::TYPE_UNKNOWN;
+ else if(dep_type == "TYPE_UI")
+ compiler.type = QMakeSourceFileInfo::TYPE_UI;
+ else
+ compiler.type = QMakeSourceFileInfo::TYPE_C;
+ compilers.append(compiler);
+ }
+ }
+ }
+ { //do the path fixifying
+ QStringList paths;
+ for(x = 0; x < compilers.count(); ++x) {
+ if(!paths.contains(compilers.at(x).variable_in))
+ paths << compilers.at(x).variable_in;
+ }
+ paths << "INCLUDEPATH" << "QMAKE_INTERNAL_INCLUDED_FILES" << "PRECOMPILED_HEADER";
+ for(int y = 0; y < paths.count(); y++) {
+ QStringList &l = v[paths[y]];
+ for(QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
+ if((*it).isEmpty())
+ continue;
+ if(exists((*it)))
+ (*it) = fileFixify((*it));
+ }
+ }
+ }
+
+ if(noIO() || !doDepends())
+ QMakeSourceFileInfo::setDependencyMode(QMakeSourceFileInfo::NonRecursive);
+ for(x = 0; x < compilers.count(); ++x)
+ initCompiler(compilers.at(x));
+
+ //merge actual compiler outputs into their variable_out. This is done last so that
+ //files are already properly fixified.
+ for(QStringList::Iterator it = quc.begin(); it != quc.end(); ++it) {
+ QString tmp_out = project->values((*it) + ".output").first();
+ if(tmp_out.isEmpty())
+ continue;
+ if(project->values((*it) + ".CONFIG").indexOf("combine") != -1) {
+ QStringList &compilerInputs = project->values((*it) + ".input");
+ // Don't generate compiler output if it doesn't have input.
+ if (compilerInputs.isEmpty() || project->values(compilerInputs.first()).isEmpty())
+ continue;
+ if(tmp_out.indexOf("$") == -1) {
+ if(!verifyExtraCompiler((*it), QString())) //verify
+ continue;
+ QString out = fileFixify(tmp_out, Option::output_dir, Option::output_dir);
+ bool pre_dep = (project->values((*it) + ".CONFIG").indexOf("target_predeps") != -1);
+ if(project->variables().contains((*it) + ".variable_out")) {
+ const QStringList &var_out = project->variables().value((*it) + ".variable_out");
+ for(int i = 0; i < var_out.size(); ++i) {
+ QString v = var_out.at(i);
+ if(v == QLatin1String("SOURCES"))
+ v = "GENERATED_SOURCES";
+ else if(v == QLatin1String("OBJECTS"))
+ pre_dep = false;
+ QStringList &list = project->values(v);
+ if(!list.contains(out))
+ list.append(out);
+ }
+ } else if(project->values((*it) + ".CONFIG").indexOf("no_link") == -1) {
+ QStringList &list = project->values("OBJECTS");
+ pre_dep = false;
+ if(!list.contains(out))
+ list.append(out);
+ } else {
+ QStringList &list = project->values("UNUSED_SOURCES");
+ if(!list.contains(out))
+ list.append(out);
+ }
+ if(pre_dep) {
+ QStringList &list = project->variables()["PRE_TARGETDEPS"];
+ if(!list.contains(out))
+ list.append(out);
+ }
+ }
+ } else {
+ QStringList &tmp = project->values((*it) + ".input");
+ for(QStringList::Iterator it2 = tmp.begin(); it2 != tmp.end(); ++it2) {
+ const QStringList inputs = project->values((*it2));
+ for(QStringList::ConstIterator input = inputs.constBegin(); input != inputs.constEnd(); ++input) {
+ if((*input).isEmpty())
+ continue;
+ QString in = Option::fixPathToTargetOS((*input), false);
+ if(!verifyExtraCompiler((*it), in)) //verify
+ continue;
+ QString out = replaceExtraCompilerVariables(tmp_out, (*input), QString());
+ out = fileFixify(out, Option::output_dir, Option::output_dir);
+ bool pre_dep = (project->values((*it) + ".CONFIG").indexOf("target_predeps") != -1);
+ if(project->variables().contains((*it) + ".variable_out")) {
+ const QStringList &var_out = project->variables().value((*it) + ".variable_out");
+ for(int i = 0; i < var_out.size(); ++i) {
+ QString v = var_out.at(i);
+ if(v == QLatin1String("SOURCES"))
+ v = "GENERATED_SOURCES";
+ else if(v == QLatin1String("OBJECTS"))
+ pre_dep = false;
+ QStringList &list = project->values(v);
+ if(!list.contains(out))
+ list.append(out);
+ }
+ } else if(project->values((*it) + ".CONFIG").indexOf("no_link") == -1) {
+ pre_dep = false;
+ QStringList &list = project->values("OBJECTS");
+ if(!list.contains(out))
+ list.append(out);
+ } else {
+ QStringList &list = project->values("UNUSED_SOURCES");
+ if(!list.contains(out))
+ list.append(out);
+ }
+ if(pre_dep) {
+ QStringList &list = project->variables()["PRE_TARGETDEPS"];
+ if(!list.contains(out))
+ list.append(out);
+ }
+ }
+ }
+ }
+ }
+
+ //handle dependencies
+ depHeuristicsCache.clear();
+ if(!noIO()) {
+ // dependency paths
+ QStringList incDirs = v["DEPENDPATH"] + v["QMAKE_ABSOLUTE_SOURCE_PATH"];
+ if(project->isActiveConfig("depend_includepath"))
+ incDirs += v["INCLUDEPATH"];
+ if(!project->isActiveConfig("no_include_pwd")) {
+ QString pwd = qmake_getpwd();
+ if(pwd.isEmpty())
+ pwd = ".";
+ incDirs += pwd;
+ }
+ QList<QMakeLocalFileName> deplist;
+ for(QStringList::Iterator it = incDirs.begin(); it != incDirs.end(); ++it)
+ deplist.append(QMakeLocalFileName(unescapeFilePath((*it))));
+ QMakeSourceFileInfo::setDependencyPaths(deplist);
+ debug_msg(1, "Dependency Directories: %s", incDirs.join(" :: ").toLatin1().constData());
+ //cache info
+ if(project->isActiveConfig("qmake_cache")) {
+ QString cache_file;
+ if(!project->isEmpty("QMAKE_INTERNAL_CACHE_FILE")) {
+ cache_file = Option::fixPathToLocalOS(project->first("QMAKE_INTERNAL_CACHE_FILE"));
+ } else {
+ cache_file = ".qmake.internal.cache";
+ if(project->isActiveConfig("build_pass"))
+ cache_file += ".BUILD." + project->first("BUILD_PASS");
+ }
+ if(cache_file.indexOf(QDir::separator()) == -1)
+ cache_file.prepend(Option::output_dir + QDir::separator());
+ QMakeSourceFileInfo::setCacheFile(cache_file);
+ }
+
+ //add to dependency engine
+ for(x = 0; x < compilers.count(); ++x) {
+ const MakefileGenerator::Compiler &comp = compilers.at(x);
+ if(!(comp.flags & Compiler::CompilerNoCheckDeps))
+ addSourceFiles(v[comp.variable_in], QMakeSourceFileInfo::SEEK_DEPS,
+ (QMakeSourceFileInfo::SourceFileType)comp.type);
+ }
+ }
+
+ processSources(); //remove anything in SOURCES which is included (thus it need not be linked in)
+
+ //all sources and generated sources must be turned into objects at some point (the one builtin compiler)
+ v["OBJECTS"] += createObjectList(v["SOURCES"]) + createObjectList(v["GENERATED_SOURCES"]);
+
+ //Translation files
+ if(!project->isEmpty("TRANSLATIONS")) {
+ QStringList &trf = project->values("TRANSLATIONS");
+ for(QStringList::Iterator it = trf.begin(); it != trf.end(); ++it)
+ (*it) = Option::fixPathToLocalOS((*it));
+ }
+
+ { //get the output_dir into the pwd
+ if(fileFixify(Option::output_dir) != fileFixify(qmake_getpwd()))
+ project->values("INCLUDEPATH").append(fileFixify(Option::output_dir,
+ Option::output_dir,
+ Option::output_dir));
+ }
+
+ //fix up the target deps
+ QString fixpaths[] = { QString("PRE_TARGETDEPS"), QString("POST_TARGETDEPS"), QString() };
+ for(int path = 0; !fixpaths[path].isNull(); path++) {
+ QStringList &l = v[fixpaths[path]];
+ for(QStringList::Iterator val_it = l.begin(); val_it != l.end(); ++val_it) {
+ if(!(*val_it).isEmpty())
+ (*val_it) = escapeDependencyPath(Option::fixPathToTargetOS((*val_it), false, false));
+ }
+ }
+
+ //extra depends
+ if(!project->isEmpty("DEPENDS")) {
+ QStringList &l = v["DEPENDS"];
+ for(QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
+ QStringList files = v[(*it) + ".file"] + v[(*it) + ".files"]; //why do I support such evil things?
+ for(QStringList::Iterator file_it = files.begin(); file_it != files.end(); ++file_it) {
+ QStringList &out_deps = findDependencies(*file_it);
+ QStringList &in_deps = v[(*it) + ".depends"]; //even more evilness..
+ for(QStringList::Iterator dep_it = in_deps.begin(); dep_it != in_deps.end(); ++dep_it) {
+ if(exists(*dep_it)) {
+ out_deps.append(*dep_it);
+ } else {
+ QString dir, regex = Option::fixPathToLocalOS((*dep_it));
+ if(regex.lastIndexOf(Option::dir_sep) != -1) {
+ dir = regex.left(regex.lastIndexOf(Option::dir_sep) + 1);
+ regex = regex.right(regex.length() - dir.length());
+ }
+ QStringList files = QDir(dir).entryList(QStringList(regex));
+ if(files.isEmpty()) {
+ warn_msg(WarnLogic, "Dependency for [%s]: Not found %s", (*file_it).toLatin1().constData(),
+ (*dep_it).toLatin1().constData());
+ } else {
+ for(int i = 0; i < files.count(); i++)
+ out_deps.append(dir + files[i]);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // escape qmake command
+ if (!project->isEmpty("QMAKE_QMAKE")) {
+ project->values("QMAKE_QMAKE") = escapeFilePaths(project->values("QMAKE_QMAKE"));
+ }
+}
+
+bool
+MakefileGenerator::processPrlFile(QString &file)
+{
+ bool ret = false, try_replace_file=false;
+ QString meta_file, orig_file = file;
+ if(QMakeMetaInfo::libExists(file)) {
+ try_replace_file = true;
+ meta_file = file;
+ file = "";
+ } else {
+ QString tmp = file;
+ int ext = tmp.lastIndexOf('.');
+ if(ext != -1)
+ tmp = tmp.left(ext);
+ meta_file = tmp;
+ }
+// meta_file = fileFixify(meta_file);
+ QString real_meta_file = Option::fixPathToLocalOS(meta_file);
+ if(!meta_file.isEmpty()) {
+ QString f = fileFixify(real_meta_file, qmake_getpwd(), Option::output_dir);
+ if(QMakeMetaInfo::libExists(f)) {
+ QMakeMetaInfo libinfo;
+ debug_msg(1, "Processing PRL file: %s", real_meta_file.toLatin1().constData());
+ if(!libinfo.readLib(f)) {
+ fprintf(stderr, "Error processing meta file: %s\n", real_meta_file.toLatin1().constData());
+ } else if(project->isActiveConfig("no_read_prl_" + libinfo.type().toLower())) {
+ debug_msg(2, "Ignored meta file %s [%s]", real_meta_file.toLatin1().constData(), libinfo.type().toLatin1().constData());
+ } else {
+ ret = true;
+ QMap<QString, QStringList> &vars = libinfo.variables();
+ for(QMap<QString, QStringList>::Iterator it = vars.begin(); it != vars.end(); ++it)
+ processPrlVariable(it.key(), it.value());
+ if(try_replace_file && !libinfo.isEmpty("QMAKE_PRL_TARGET")) {
+ QString dir;
+ int slsh = real_meta_file.lastIndexOf(Option::dir_sep);
+ if(slsh != -1)
+ dir = real_meta_file.left(slsh+1);
+ file = libinfo.first("QMAKE_PRL_TARGET");
+ if(QDir::isRelativePath(file))
+ file.prepend(dir);
+ }
+ }
+ }
+ if(ret) {
+ QString mf = QMakeMetaInfo::findLib(meta_file);
+ if(project->values("QMAKE_PRL_INTERNAL_FILES").indexOf(mf) == -1)
+ project->values("QMAKE_PRL_INTERNAL_FILES").append(mf);
+ if(project->values("QMAKE_INTERNAL_INCLUDED_FILES").indexOf(mf) == -1)
+ project->values("QMAKE_INTERNAL_INCLUDED_FILES").append(mf);
+ }
+ }
+ if(try_replace_file && file.isEmpty()) {
+#if 0
+ warn_msg(WarnLogic, "Found prl [%s] file with no target [%s]!", meta_file.toLatin1().constData(),
+ orig_file.toLatin1().constData());
+#endif
+ file = orig_file;
+ }
+ return ret;
+}
+
+void
+MakefileGenerator::filterIncludedFiles(const QString &var)
+{
+ QStringList &inputs = project->values(var);
+ for(QStringList::Iterator input = inputs.begin(); input != inputs.end(); ) {
+ if(QMakeSourceFileInfo::included((*input)) > 0)
+ input = inputs.erase(input);
+ else
+ ++input;
+ }
+}
+
+void
+MakefileGenerator::processPrlVariable(const QString &var, const QStringList &l)
+{
+ if(var == "QMAKE_PRL_LIBS") {
+ QString where = "QMAKE_LIBS";
+ if(!project->isEmpty("QMAKE_INTERNAL_PRL_LIBS"))
+ where = project->first("QMAKE_INTERNAL_PRL_LIBS");
+ QStringList &out = project->values(where);
+ for(QStringList::ConstIterator it = l.begin(); it != l.end(); ++it) {
+ if(out.indexOf((*it)) == -1)
+ out.append((*it));
+ }
+ } else if(var == "QMAKE_PRL_DEFINES") {
+ QStringList &out = project->values("DEFINES");
+ for(QStringList::ConstIterator it = l.begin(); it != l.end(); ++it) {
+ if(out.indexOf((*it)) == -1 &&
+ project->values("PRL_EXPORT_DEFINES").indexOf((*it)) == -1)
+ out.append((*it));
+ }
+ }
+}
+
+void
+MakefileGenerator::processPrlFiles()
+{
+ QHash<QString, bool> processed;
+ for(bool ret = false; true; ret = false) {
+ //read in any prl files included..
+ QStringList l_out;
+ QString where = "QMAKE_LIBS";
+ if(!project->isEmpty("QMAKE_INTERNAL_PRL_LIBS"))
+ where = project->first("QMAKE_INTERNAL_PRL_LIBS");
+ QStringList &l = project->values(where);
+ for(QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
+ QString file = (*it);
+ if(!processed.contains(file) && processPrlFile(file)) {
+ processed.insert(file, true);
+ ret = true;
+ }
+ if(!file.isEmpty())
+ l_out.append(file);
+ }
+ if(ret)
+ l = l_out;
+ else
+ break;
+ }
+}
+
+void
+MakefileGenerator::writePrlFile(QTextStream &t)
+{
+ QString target = project->first("TARGET");
+ int slsh = target.lastIndexOf(Option::dir_sep);
+ if(slsh != -1)
+ target = target.right(target.length() - slsh - 1);
+ QString bdir = Option::output_dir;
+ if(bdir.isEmpty())
+ bdir = qmake_getpwd();
+ t << "QMAKE_PRL_BUILD_DIR = " << bdir << endl;
+
+ if(!project->projectFile().isEmpty() && project->projectFile() != "-")
+ t << "QMAKE_PRO_INPUT = " << project->projectFile().section('/', -1) << endl;
+
+ if(!project->isEmpty("QMAKE_ABSOLUTE_SOURCE_PATH"))
+ t << "QMAKE_PRL_SOURCE_DIR = " << project->first("QMAKE_ABSOLUTE_SOURCE_PATH") << endl;
+ t << "QMAKE_PRL_TARGET = " << target << endl;
+ if(!project->isEmpty("PRL_EXPORT_DEFINES"))
+ t << "QMAKE_PRL_DEFINES = " << project->values("PRL_EXPORT_DEFINES").join(" ") << endl;
+ if(!project->isEmpty("PRL_EXPORT_CFLAGS"))
+ t << "QMAKE_PRL_CFLAGS = " << project->values("PRL_EXPORT_CFLAGS").join(" ") << endl;
+ if(!project->isEmpty("PRL_EXPORT_CXXFLAGS"))
+ t << "QMAKE_PRL_CXXFLAGS = " << project->values("PRL_EXPORT_CXXFLAGS").join(" ") << endl;
+ if(!project->isEmpty("CONFIG"))
+ t << "QMAKE_PRL_CONFIG = " << project->values("CONFIG").join(" ") << endl;
+ if(!project->isEmpty("TARGET_VERSION_EXT"))
+ t << "QMAKE_PRL_VERSION = " << project->first("TARGET_VERSION_EXT") << endl;
+ else if(!project->isEmpty("VERSION"))
+ t << "QMAKE_PRL_VERSION = " << project->first("VERSION") << endl;
+ if(project->isActiveConfig("staticlib") || project->isActiveConfig("explicitlib")) {
+ QStringList libs;
+ if(!project->isEmpty("QMAKE_INTERNAL_PRL_LIBS"))
+ libs = project->values("QMAKE_INTERNAL_PRL_LIBS");
+ else
+ libs << "QMAKE_LIBS"; //obvious one
+ t << "QMAKE_PRL_LIBS = ";
+ for(QStringList::Iterator it = libs.begin(); it != libs.end(); ++it)
+ t << project->values((*it)).join(" ") << " ";
+ t << endl;
+ }
+}
+
+bool
+MakefileGenerator::writeProjectMakefile()
+{
+ usePlatformDir();
+ QTextStream t(&Option::output);
+
+ //header
+ writeHeader(t);
+
+ QList<SubTarget*> targets;
+ {
+ QStringList builds = project->values("BUILDS");
+ for(QStringList::Iterator it = builds.begin(); it != builds.end(); ++it) {
+ SubTarget *st = new SubTarget;
+ targets.append(st);
+ st->makefile = "$(MAKEFILE)." + (*it);
+ st->name = (*it);
+ st->target = project->isEmpty((*it) + ".target") ? (*it) : project->first((*it) + ".target");
+ }
+ }
+ if(project->isActiveConfig("build_all")) {
+ t << "first: all" << endl;
+ QList<SubTarget*>::Iterator it;
+
+ //install
+ t << "install: ";
+ for(it = targets.begin(); it != targets.end(); ++it)
+ t << (*it)->target << "-install ";
+ t << endl;
+
+ //uninstall
+ t << "uninstall: ";
+ for(it = targets.begin(); it != targets.end(); ++it)
+ t << (*it)->target << "-uninstall ";
+ t << endl;
+ } else {
+ t << "first: " << targets.first()->target << endl
+ << "install: " << targets.first()->target << "-install" << endl
+ << "uninstall: " << targets.first()->target << "-uninstall" << endl;
+ }
+
+ writeSubTargets(t, targets, SubTargetsNoFlags);
+ if(!project->isActiveConfig("no_autoqmake")) {
+ for(QList<SubTarget*>::Iterator it = targets.begin(); it != targets.end(); ++it)
+ t << (*it)->makefile << ": " <<
+ Option::fixPathToTargetOS(fileFixify(Option::output.fileName())) << endl;
+ }
+ qDeleteAll(targets);
+ return true;
+}
+
+bool
+MakefileGenerator::write()
+{
+ if(!project)
+ return false;
+ writePrlFile();
+ if(Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE || //write makefile
+ Option::qmake_mode == Option::QMAKE_GENERATE_PROJECT) {
+ QTextStream t(&Option::output);
+ if(!writeMakefile(t)) {
+#if 1
+ warn_msg(WarnLogic, "Unable to generate output for: %s [TEMPLATE %s]",
+ Option::output.fileName().toLatin1().constData(),
+ project->first("TEMPLATE").toLatin1().constData());
+ if(Option::output.exists())
+ Option::output.remove();
+#endif
+ }
+ }
+ return true;
+}
+
+QString
+MakefileGenerator::prlFileName(bool fixify)
+{
+ QString ret = project->first("TARGET_PRL");;
+ if(ret.isEmpty())
+ ret = project->first("TARGET");
+ int slsh = ret.lastIndexOf(Option::dir_sep);
+ if(slsh != -1)
+ ret = ret.right(ret.length() - slsh);
+ if(!ret.endsWith(Option::prl_ext)) {
+ int dot = ret.indexOf('.');
+ if(dot != -1)
+ ret = ret.left(dot);
+ ret += Option::prl_ext;
+ }
+ if(!project->isEmpty("QMAKE_BUNDLE"))
+ ret.prepend(project->first("QMAKE_BUNDLE") + Option::dir_sep);
+ if(fixify) {
+ if(!project->isEmpty("DESTDIR"))
+ ret.prepend(project->first("DESTDIR"));
+ ret = Option::fixPathToLocalOS(fileFixify(ret, qmake_getpwd(), Option::output_dir));
+ }
+ return ret;
+}
+
+void
+MakefileGenerator::writePrlFile()
+{
+ if((Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE ||
+ Option::qmake_mode == Option::QMAKE_GENERATE_PRL)
+ && project->values("QMAKE_FAILED_REQUIREMENTS").isEmpty()
+ && project->isActiveConfig("create_prl")
+ && (project->first("TEMPLATE") == "lib"
+ || project->first("TEMPLATE") == "vclib")
+ && !project->isActiveConfig("plugin")) { //write prl file
+ QString local_prl = prlFileName();
+ QString prl = fileFixify(local_prl);
+ mkdir(fileInfo(local_prl).path());
+ QFile ft(local_prl);
+ if(ft.open(QIODevice::WriteOnly)) {
+ project->values("ALL_DEPS").append(prl);
+ project->values("QMAKE_INTERNAL_PRL_FILE").append(prl);
+ QTextStream t(&ft);
+ writePrlFile(t);
+ }
+ }
+}
+
+// Manipulate directories, so it's possible to build
+// several cross-platform targets concurrently
+void
+MakefileGenerator::usePlatformDir()
+{
+ QString pltDir(project->first("QMAKE_PLATFORM_DIR"));
+ if(pltDir.isEmpty())
+ return;
+ QChar sep = QDir::separator();
+ QString slashPltDir = sep + pltDir;
+
+ QString dirs[] = { QString("OBJECTS_DIR"), QString("DESTDIR"), QString("QMAKE_PKGCONFIG_DESTDIR"),
+ QString("SUBLIBS_DIR"), QString("DLLDESTDIR"), QString("QMAKE_LIBTOOL_DESTDIR"),
+ QString("PRECOMPILED_DIR"), QString("QMAKE_LIBDIR_QT"), QString() };
+ for(int i = 0; !dirs[i].isEmpty(); ++i) {
+ QString filePath = project->first(dirs[i]);
+ project->values(dirs[i]) = QStringList(filePath + (filePath.isEmpty() ? pltDir : slashPltDir));
+ }
+
+ QString libs[] = { QString("QMAKE_LIBS_QT"), QString("QMAKE_LIBS_QT_THREAD"), QString("QMAKE_LIBS_QT_ENTRY"), QString() };
+ for(int i = 0; !libs[i].isEmpty(); ++i) {
+ QString filePath = project->first(libs[i]);
+ int fpi = filePath.lastIndexOf(sep);
+ if(fpi == -1)
+ project->values(libs[i]).prepend(pltDir + sep);
+ else
+ project->values(libs[i]) = QStringList(filePath.left(fpi) + slashPltDir + filePath.mid(fpi));
+ }
+}
+
+void
+MakefileGenerator::writeObj(QTextStream &t, const QString &src)
+{
+ QStringList &srcl = project->values(src);
+ QStringList objl = createObjectList(srcl);
+
+ QStringList::Iterator oit = objl.begin();
+ QStringList::Iterator sit = srcl.begin();
+ QString stringSrc("$src");
+ QString stringObj("$obj");
+ for(;sit != srcl.end() && oit != objl.end(); ++oit, ++sit) {
+ if((*sit).isEmpty())
+ continue;
+
+ t << escapeDependencyPath((*oit)) << ": " << escapeDependencyPath((*sit)) << " " << escapeDependencyPaths(findDependencies((*sit))).join(" \\\n\t\t");
+
+ QString comp, cimp;
+ for(QStringList::Iterator cppit = Option::cpp_ext.begin(); cppit != Option::cpp_ext.end(); ++cppit) {
+ if((*sit).endsWith((*cppit))) {
+ comp = "QMAKE_RUN_CXX";
+ cimp = "QMAKE_RUN_CXX_IMP";
+ break;
+ }
+ }
+ if(comp.isEmpty()) {
+ comp = "QMAKE_RUN_CC";
+ cimp = "QMAKE_RUN_CC_IMP";
+ }
+ bool use_implicit_rule = !project->isEmpty(cimp);
+ use_implicit_rule = false;
+ if(use_implicit_rule) {
+ if(!project->isEmpty("OBJECTS_DIR")) {
+ use_implicit_rule = false;
+ } else {
+ int dot = (*sit).lastIndexOf('.');
+ if(dot == -1 || ((*sit).left(dot) + Option::obj_ext != (*oit)))
+ use_implicit_rule = false;
+ }
+ }
+ if (!use_implicit_rule && !project->isEmpty(comp)) {
+ QString p = var(comp), srcf(*sit);
+ p.replace(stringSrc, escapeFilePath(srcf));
+ p.replace(stringObj, escapeFilePath((*oit)));
+ t << "\n\t" << p;
+ }
+ t << endl << endl;
+ }
+}
+
+QString
+MakefileGenerator::filePrefixRoot(const QString &root, const QString &path)
+{
+ QString ret(root + path);
+ if(path.length() > 2 && path[1] == ':') //c:\foo
+ ret = QString(path.mid(0, 2) + root + path.mid(2));
+ while(ret.endsWith("\\"))
+ ret = ret.left(ret.length()-1);
+ return ret;
+}
+
+void
+MakefileGenerator::writeInstalls(QTextStream &t, const QString &installs, bool noBuild)
+{
+ QString rm_dir_contents("-$(DEL_FILE)");
+ if (!isWindowsShell()) //ick
+ rm_dir_contents = "-$(DEL_FILE) -r";
+
+ QString all_installs, all_uninstalls;
+ QStringList &l = project->values(installs);
+ for(QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
+ QString pvar = (*it) + ".path";
+ if(project->values((*it) + ".CONFIG").indexOf("no_path") == -1 &&
+ project->values((*it) + ".CONFIG").indexOf("dummy_install") == -1 &&
+ project->values(pvar).isEmpty()) {
+ warn_msg(WarnLogic, "%s is not defined: install target not created\n", pvar.toLatin1().constData());
+ continue;
+ }
+
+ bool do_default = true;
+ const QString root = "$(INSTALL_ROOT)";
+ QString target, dst;
+ if(project->values((*it) + ".CONFIG").indexOf("no_path") == -1 &&
+ project->values((*it) + ".CONFIG").indexOf("dummy_install") == -1) {
+ dst = fileFixify(unescapeFilePath(project->values(pvar).first()), FileFixifyAbsolute, false);
+ if(dst.right(1) != Option::dir_sep)
+ dst += Option::dir_sep;
+ }
+ dst = escapeFilePath(dst);
+
+ QStringList tmp, uninst = project->values((*it) + ".uninstall");
+ //other
+ tmp = project->values((*it) + ".extra");
+ if(tmp.isEmpty())
+ tmp = project->values((*it) + ".commands"); //to allow compatible name
+ if(!tmp.isEmpty()) {
+ do_default = false;
+ if(!target.isEmpty())
+ target += "\n\t";
+ target += tmp.join(" ");
+ }
+ //masks
+ tmp = findFilesInVPATH(project->values((*it) + ".files"), VPATH_NoFixify);
+ tmp = fileFixify(tmp, FileFixifyAbsolute);
+ if(!tmp.isEmpty()) {
+ if(!target.isEmpty())
+ target += "\n";
+ do_default = false;
+ for(QStringList::Iterator wild_it = tmp.begin(); wild_it != tmp.end(); ++wild_it) {
+ QString wild = Option::fixPathToLocalOS((*wild_it), false, false);
+ QString dirstr = qmake_getpwd(), filestr = wild;
+ int slsh = filestr.lastIndexOf(Option::dir_sep);
+ if(slsh != -1) {
+ dirstr = filestr.left(slsh+1);
+ filestr = filestr.right(filestr.length() - slsh - 1);
+ }
+ if(dirstr.right(Option::dir_sep.length()) != Option::dir_sep)
+ dirstr += Option::dir_sep;
+ if(exists(wild)) { //real file
+ QString file = wild;
+ QFileInfo fi(fileInfo(wild));
+ if(!target.isEmpty())
+ target += "\t";
+ QString dst_file = filePrefixRoot(root, dst);
+ if(fi.isDir() && project->isActiveConfig("copy_dir_files")) {
+ if(!dst_file.endsWith(Option::dir_sep))
+ dst_file += Option::dir_sep;
+ dst_file += fi.fileName();
+ }
+ QString cmd;
+ if (fi.isDir())
+ cmd = "-$(INSTALL_DIR)";
+ else if (fi.isExecutable())
+ cmd = "-$(INSTALL_PROGRAM)";
+ else
+ cmd = "-$(INSTALL_FILE)";
+ cmd += " " + escapeFilePath(wild) + " " + dst_file + "\n";
+ target += cmd;
+ if(!project->isActiveConfig("debug") && !project->isActiveConfig("nostrip") &&
+ !fi.isDir() && fi.isExecutable() && !project->isEmpty("QMAKE_STRIP"))
+ target += QString("\t-") + var("QMAKE_STRIP") + " " +
+ filePrefixRoot(root, fileFixify(dst + filestr, FileFixifyAbsolute, false)) + "\n";
+ if(!uninst.isEmpty())
+ uninst.append("\n\t");
+ uninst.append(rm_dir_contents + " " + filePrefixRoot(root, fileFixify(dst + filestr, FileFixifyAbsolute, false)));
+ continue;
+ }
+ QString local_dirstr = Option::fixPathToLocalOS(dirstr, true);
+ QStringList files = QDir(local_dirstr).entryList(QStringList(filestr));
+ if(project->values((*it) + ".CONFIG").indexOf("no_check_exist") != -1 && files.isEmpty()) {
+ if(!target.isEmpty())
+ target += "\t";
+ QString dst_file = filePrefixRoot(root, dst);
+ QFileInfo fi(fileInfo(wild));
+ QString cmd = QString(fi.isExecutable() ? "-$(INSTALL_PROGRAM)" : "-$(INSTALL_FILE)") + " " +
+ wild + " " + dst_file + "\n";
+ target += cmd;
+ if(!uninst.isEmpty())
+ uninst.append("\n\t");
+ uninst.append(rm_dir_contents + " " + filePrefixRoot(root, fileFixify(dst + filestr, FileFixifyAbsolute, false)));
+ }
+ for(int x = 0; x < files.count(); x++) {
+ QString file = files[x];
+ if(file == "." || file == "..") //blah
+ continue;
+ if(!uninst.isEmpty())
+ uninst.append("\n\t");
+ uninst.append(rm_dir_contents + " " + filePrefixRoot(root, fileFixify(dst + file, FileFixifyAbsolute, false)));
+ QFileInfo fi(fileInfo(dirstr + file));
+ if(!target.isEmpty())
+ target += "\t";
+ QString dst_file = filePrefixRoot(root, fileFixify(dst, FileFixifyAbsolute, false));
+ if(fi.isDir() && project->isActiveConfig("copy_dir_files")) {
+ if(!dst_file.endsWith(Option::dir_sep))
+ dst_file += Option::dir_sep;
+ dst_file += fi.fileName();
+ }
+ QString cmd = QString(fi.isDir() ? "-$(INSTALL_DIR)" : "-$(INSTALL_FILE)") + " " +
+ dirstr + file + " " + dst_file + "\n";
+ target += cmd;
+ if(!project->isActiveConfig("debug") && !project->isActiveConfig("nostrip") &&
+ !fi.isDir() && fi.isExecutable() && !project->isEmpty("QMAKE_STRIP"))
+ target += QString("\t-") + var("QMAKE_STRIP") + " " +
+ filePrefixRoot(root, fileFixify(dst + file, FileFixifyAbsolute, false)) +
+ "\n";
+ }
+ }
+ }
+ //default?
+ if(do_default) {
+ target = defaultInstall((*it));
+ uninst = project->values((*it) + ".uninstall");
+ }
+
+ if(!target.isEmpty() || project->values((*it) + ".CONFIG").indexOf("dummy_install") != -1) {
+ if(noBuild || project->values((*it) + ".CONFIG").indexOf("no_build") != -1)
+ t << "install_" << (*it) << ":";
+ else if(project->isActiveConfig("build_all"))
+ t << "install_" << (*it) << ": all";
+ else
+ t << "install_" << (*it) << ": first";
+ const QStringList &deps = project->values((*it) + ".depends");
+ if(!deps.isEmpty()) {
+ for(QStringList::ConstIterator dep_it = deps.begin(); dep_it != deps.end(); ++dep_it) {
+ QString targ = var((*dep_it) + ".target");
+ if(targ.isEmpty())
+ targ = (*dep_it);
+ t << " " << escapeDependencyPath(targ);
+ }
+ }
+ if(project->isEmpty("QMAKE_NOFORCE"))
+ t << " FORCE";
+ t << "\n\t";
+ const QStringList &dirs = project->values(pvar);
+ for(QStringList::ConstIterator pit = dirs.begin(); pit != dirs.end(); ++pit) {
+ QString tmp_dst = fileFixify((*pit), FileFixifyAbsolute, false);
+ if (!isWindowsShell() && tmp_dst.right(1) != Option::dir_sep)
+ tmp_dst += Option::dir_sep;
+ t << mkdir_p_asstring(filePrefixRoot(root, tmp_dst)) << "\n\t";
+ }
+ t << target << endl << endl;
+ if(!uninst.isEmpty()) {
+ t << "uninstall_" << (*it) << ": ";
+ if(project->isEmpty("QMAKE_NOFORCE"))
+ t << " FORCE";
+ t << "\n\t"
+ << uninst.join(" ") << "\n\t"
+ << "-$(DEL_DIR) " << filePrefixRoot(root, dst) << " " << endl << endl;
+ }
+ t << endl;
+
+ if(project->values((*it) + ".CONFIG").indexOf("no_default_install") == -1) {
+ all_installs += QString("install_") + (*it) + " ";
+ if(!uninst.isEmpty())
+ all_uninstalls += "uninstall_" + (*it) + " ";
+ }
+ } else {
+ debug_msg(1, "no definition for install %s: install target not created",(*it).toLatin1().constData());
+ }
+ }
+ t << "install: " << var("INSTALLDEPS") << " " << all_installs;
+ if(project->isEmpty("QMAKE_NOFORCE"))
+ t << " FORCE";
+ t << "\n\n";
+ t << "uninstall: " << all_uninstalls << " " << var("UNINSTALLDEPS");
+ if(project->isEmpty("QMAKE_NOFORCE"))
+ t << " FORCE";
+ t << "\n\n";
+}
+
+QString
+MakefileGenerator::var(const QString &var)
+{
+ return val(project->values(var));
+}
+
+QString
+MakefileGenerator::val(const QStringList &varList)
+{
+ return valGlue(varList, "", " ", "");
+}
+
+QString
+MakefileGenerator::varGlue(const QString &var, const QString &before, const QString &glue, const QString &after)
+{
+ return valGlue(project->values(var), before, glue, after);
+}
+
+QString
+MakefileGenerator::valGlue(const QStringList &varList, const QString &before, const QString &glue, const QString &after)
+{
+ QString ret;
+ for(QStringList::ConstIterator it = varList.begin(); it != varList.end(); ++it) {
+ if(!(*it).isEmpty()) {
+ if(!ret.isEmpty())
+ ret += glue;
+ ret += (*it);
+ }
+ }
+ return ret.isEmpty() ? QString("") : before + ret + after;
+}
+
+
+QString
+MakefileGenerator::varList(const QString &var)
+{
+ return valList(project->values(var));
+}
+
+QString
+MakefileGenerator::valList(const QStringList &varList)
+{
+ return valGlue(varList, "", " \\\n\t\t", "");
+}
+
+QStringList
+MakefileGenerator::createObjectList(const QStringList &sources)
+{
+ QStringList ret;
+ QString objdir;
+ if(!project->values("OBJECTS_DIR").isEmpty())
+ objdir = project->first("OBJECTS_DIR");
+ for(QStringList::ConstIterator it = sources.begin(); it != sources.end(); ++it) {
+ QFileInfo fi(fileInfo(Option::fixPathToLocalOS((*it))));
+ QString dir;
+ if(objdir.isEmpty() && project->isActiveConfig("object_with_source")) {
+ QString fName = Option::fixPathToTargetOS((*it), false);
+ int dl = fName.lastIndexOf(Option::dir_sep);
+ if(dl != -1)
+ dir = fName.left(dl + 1);
+ } else {
+ dir = objdir;
+ }
+ ret.append(dir + fi.completeBaseName() + Option::obj_ext);
+ }
+ return ret;
+}
+
+ReplaceExtraCompilerCacheKey::ReplaceExtraCompilerCacheKey(const QString &v, const QStringList &i, const QStringList &o)
+{
+ hash = 0;
+ pwd = qmake_getpwd();
+ var = v;
+ {
+ QStringList il = i;
+ il.sort();
+ in = il.join("::");
+ }
+ {
+ QStringList ol = o;
+ ol.sort();
+ out = ol.join("::");
+ }
+}
+
+bool ReplaceExtraCompilerCacheKey::operator==(const ReplaceExtraCompilerCacheKey &f) const
+{
+ return (hashCode() == f.hashCode() &&
+ f.in == in &&
+ f.out == out &&
+ f.var == var &&
+ f.pwd == pwd);
+}
+
+
+QString
+MakefileGenerator::replaceExtraCompilerVariables(const QString &orig_var, const QStringList &in, const QStringList &out)
+{
+ //lazy cache
+ ReplaceExtraCompilerCacheKey cacheKey(orig_var, in, out);
+ QString cacheVal = extraCompilerVariablesCache.value(cacheKey);
+ if(!cacheVal.isNull())
+ return cacheVal;
+
+ //do the work
+ QString ret = orig_var;
+ QRegExp reg_var("\\$\\{.*\\}");
+ reg_var.setMinimal(true);
+ for(int rep = 0; (rep = reg_var.indexIn(ret, rep)) != -1; ) {
+ QStringList val;
+ const QString var = ret.mid(rep + 2, reg_var.matchedLength() - 3);
+ bool filePath = false;
+ if(val.isEmpty() && var.startsWith(QLatin1String("QMAKE_VAR_"))) {
+ const QString varname = var.mid(10);
+ val += project->values(varname);
+ }
+ if(val.isEmpty() && var.startsWith(QLatin1String("QMAKE_VAR_FIRST_"))) {
+ const QString varname = var.mid(12);
+ val += project->first(varname);
+ }
+
+ if(val.isEmpty() && !in.isEmpty()) {
+ if(var.startsWith(QLatin1String("QMAKE_FUNC_FILE_IN_"))) {
+ filePath = true;
+ const QString funcname = var.mid(19);
+ val += project->expand(funcname, QList<QStringList>() << in);
+ } else if(var == QLatin1String("QMAKE_FILE_BASE") || var == QLatin1String("QMAKE_FILE_IN_BASE")) {
+ //filePath = true;
+ for(int i = 0; i < in.size(); ++i) {
+ QFileInfo fi(fileInfo(Option::fixPathToLocalOS(in.at(i))));
+ QString base = fi.completeBaseName();
+ if(base.isNull())
+ base = fi.fileName();
+ val += base;
+ }
+ } else if(var == QLatin1String("QMAKE_FILE_PATH") || var == QLatin1String("QMAKE_FILE_IN_PATH")) {
+ filePath = true;
+ for(int i = 0; i < in.size(); ++i)
+ val += fileInfo(Option::fixPathToLocalOS(in.at(i))).path();
+ } else if(var == QLatin1String("QMAKE_FILE_NAME") || var == QLatin1String("QMAKE_FILE_IN")) {
+ filePath = true;
+ for(int i = 0; i < in.size(); ++i)
+ val += fileInfo(Option::fixPathToLocalOS(in.at(i))).filePath();
+
+ }
+ }
+ if(val.isEmpty() && !out.isEmpty()) {
+ if(var.startsWith(QLatin1String("QMAKE_FUNC_FILE_OUT_"))) {
+ filePath = true;
+ const QString funcname = var.mid(20);
+ val += project->expand(funcname, QList<QStringList>() << out);
+ } else if(var == QLatin1String("QMAKE_FILE_OUT")) {
+ filePath = true;
+ for(int i = 0; i < out.size(); ++i)
+ val += fileInfo(Option::fixPathToLocalOS(out.at(i))).filePath();
+ } else if(var == QLatin1String("QMAKE_FILE_OUT_BASE")) {
+ //filePath = true;
+ for(int i = 0; i < out.size(); ++i) {
+ QFileInfo fi(fileInfo(Option::fixPathToLocalOS(out.at(i))));
+ QString base = fi.completeBaseName();
+ if(base.isNull())
+ base = fi.fileName();
+ val += base;
+ }
+ }
+ }
+ if(val.isEmpty() && var.startsWith(QLatin1String("QMAKE_FUNC_"))) {
+ const QString funcname = var.mid(11);
+ val += project->expand(funcname, QList<QStringList>() << in << out);
+ }
+
+ if(!val.isEmpty()) {
+ QString fullVal;
+ if(filePath) {
+ for(int i = 0; i < val.size(); ++i) {
+ const QString file = Option::fixPathToTargetOS(unescapeFilePath(val.at(i)), false);
+ if(!fullVal.isEmpty())
+ fullVal += " ";
+ fullVal += escapeFilePath(file);
+ }
+ } else {
+ fullVal = val.join(" ");
+ }
+ ret.replace(rep, reg_var.matchedLength(), fullVal);
+ rep += fullVal.length();
+ } else {
+ rep += reg_var.matchedLength();
+ }
+ }
+
+ //cache the value
+ extraCompilerVariablesCache.insert(cacheKey, ret);
+ return ret;
+}
+
+bool
+MakefileGenerator::verifyExtraCompiler(const QString &comp, const QString &file_unfixed)
+{
+ if(noIO())
+ return false;
+ const QString file = Option::fixPathToLocalOS(file_unfixed);
+
+ if(project->values(comp + ".CONFIG").indexOf("moc_verify") != -1) {
+ if(!file.isNull()) {
+ QMakeSourceFileInfo::addSourceFile(file, QMakeSourceFileInfo::SEEK_MOCS);
+ if(!mocable(file))
+ return false;
+ }
+ } else if(project->values(comp + ".CONFIG").indexOf("function_verify") != -1) {
+ QString tmp_out = project->values(comp + ".output").first();
+ if(tmp_out.isEmpty())
+ return false;
+ QStringList verify_function = project->values(comp + ".verify_function");
+ if(verify_function.isEmpty())
+ return false;
+
+ for(int i = 0; i < verify_function.size(); ++i) {
+ bool invert = false;
+ QString verify = verify_function.at(i);
+ if(verify.at(0) == QLatin1Char('!')) {
+ invert = true;
+ verify = verify.mid(1);
+ }
+
+ if(project->values(comp + ".CONFIG").indexOf("combine") != -1) {
+ bool pass = project->test(verify, QList<QStringList>() << QStringList(tmp_out) << QStringList(file));
+ if(invert)
+ pass = !pass;
+ if(!pass)
+ return false;
+ } else {
+ QStringList &tmp = project->values(comp + ".input");
+ for(QStringList::Iterator it = tmp.begin(); it != tmp.end(); ++it) {
+ QStringList &inputs = project->values((*it));
+ for(QStringList::Iterator input = inputs.begin(); input != inputs.end(); ++input) {
+ if((*input).isEmpty())
+ continue;
+ QString in = fileFixify(Option::fixPathToTargetOS((*input), false));
+ if(in == file) {
+ bool pass = project->test(verify,
+ QList<QStringList>() << QStringList(replaceExtraCompilerVariables(tmp_out, (*input), QString())) <<
+ QStringList(file));
+ if(invert)
+ pass = !pass;
+ if(!pass)
+ return false;
+ break;
+ }
+ }
+ }
+ }
+ }
+ } else if(project->values(comp + ".CONFIG").indexOf("verify") != -1) {
+ QString tmp_out = project->values(comp + ".output").first();
+ if(tmp_out.isEmpty())
+ return false;
+ QString tmp_cmd;
+ if(!project->isEmpty(comp + ".commands")) {
+ int argv0 = -1;
+ QStringList cmdline = project->values(comp + ".commands");
+ for(int i = 0; i < cmdline.count(); ++i) {
+ if(!cmdline.at(i).contains('=')) {
+ argv0 = i;
+ break;
+ }
+ }
+ if(argv0 != -1) {
+ cmdline[argv0] = Option::fixPathToTargetOS(cmdline.at(argv0), false);
+ tmp_cmd = cmdline.join(" ");
+ }
+ }
+
+ if(project->values(comp + ".CONFIG").indexOf("combine") != -1) {
+ QString cmd = replaceExtraCompilerVariables(tmp_cmd, QString(), tmp_out);
+ if(system(cmd.toLatin1().constData()))
+ return false;
+ } else {
+ QStringList &tmp = project->values(comp + ".input");
+ for(QStringList::Iterator it = tmp.begin(); it != tmp.end(); ++it) {
+ QStringList &inputs = project->values((*it));
+ for(QStringList::Iterator input = inputs.begin(); input != inputs.end(); ++input) {
+ if((*input).isEmpty())
+ continue;
+ QString in = fileFixify(Option::fixPathToTargetOS((*input), false));
+ if(in == file) {
+ QString out = replaceExtraCompilerVariables(tmp_out, (*input), QString());
+ QString cmd = replaceExtraCompilerVariables(tmp_cmd, in, out);
+ if(system(cmd.toLatin1().constData()))
+ return false;
+ break;
+ }
+ }
+ }
+ }
+ }
+ return true;
+}
+
+void
+MakefileGenerator::writeExtraTargets(QTextStream &t)
+{
+ QStringList &qut = project->values("QMAKE_EXTRA_TARGETS");
+ for(QStringList::Iterator it = qut.begin(); it != qut.end(); ++it) {
+ QString targ = var((*it) + ".target"),
+ cmd = var((*it) + ".commands"), deps;
+ if(targ.isEmpty())
+ targ = (*it);
+ QStringList &deplist = project->values((*it) + ".depends");
+ for(QStringList::Iterator dep_it = deplist.begin(); dep_it != deplist.end(); ++dep_it) {
+ QString dep = var((*dep_it) + ".target");
+ if(dep.isEmpty())
+ dep = (*dep_it);
+ deps += " " + escapeDependencyPath(dep);
+ }
+ if(project->values((*it) + ".CONFIG").indexOf("fix_target") != -1)
+ targ = fileFixify(targ);
+ if(project->isEmpty("QMAKE_NOFORCE") &&
+ project->values((*it) + ".CONFIG").indexOf("phony") != -1)
+ deps += QString(" ") + "FORCE";
+ t << escapeDependencyPath(targ) << ":" << deps;
+ if(!cmd.isEmpty())
+ t << "\n\t" << cmd;
+ t << endl << endl;
+ }
+}
+
+void
+MakefileGenerator::writeExtraCompilerTargets(QTextStream &t)
+{
+ QString clean_targets;
+ const QStringList &quc = project->values("QMAKE_EXTRA_COMPILERS");
+ for(QStringList::ConstIterator it = quc.begin(); it != quc.end(); ++it) {
+ QString tmp_out = fileFixify(project->values((*it) + ".output").first(),
+ Option::output_dir, Option::output_dir);
+ QString tmp_cmd;
+ if(!project->isEmpty((*it) + ".commands")) {
+ QStringList cmdline = project->values((*it) + ".commands");
+ int argv0 = findExecutable(cmdline);
+ if(argv0 != -1) {
+ cmdline[argv0] = escapeFilePath(Option::fixPathToTargetOS(cmdline.at(argv0), false));
+ tmp_cmd = cmdline.join(" ");
+ }
+ }
+ QStringList tmp_dep = project->values((*it) + ".depends");
+ QString tmp_dep_cmd;
+ if(!project->isEmpty((*it) + ".depend_command")) {
+ int argv0 = -1;
+ QStringList cmdline = project->values((*it) + ".depend_command");
+ for(int i = 0; i < cmdline.count(); ++i) {
+ if(!cmdline.at(i).contains('=')) {
+ argv0 = i;
+ break;
+ }
+ }
+ if(argv0 != -1) {
+ const QString c = Option::fixPathToLocalOS(cmdline.at(argv0), true);
+ if(exists(c)) {
+ cmdline[argv0] = escapeFilePath(Option::fixPathToLocalOS(cmdline.at(argv0), false));
+ tmp_dep_cmd = cmdline.join(" ");
+ } else {
+ cmdline[argv0] = escapeFilePath(cmdline.at(argv0));
+ }
+ }
+ }
+ QStringList &vars = project->values((*it) + ".variables");
+ if(tmp_out.isEmpty() || tmp_cmd.isEmpty())
+ continue;
+ QStringList tmp_inputs;
+ {
+ const QStringList &comp_inputs = project->values((*it) + ".input");
+ for(QStringList::ConstIterator it2 = comp_inputs.begin(); it2 != comp_inputs.end(); ++it2) {
+ const QStringList &tmp = project->values((*it2));
+ for(QStringList::ConstIterator input = tmp.begin(); input != tmp.end(); ++input) {
+ QString in = Option::fixPathToTargetOS((*input), false);
+ if(verifyExtraCompiler((*it), in))
+ tmp_inputs.append((*input));
+ }
+ }
+ }
+
+ t << "compiler_" << (*it) << "_make_all:";
+ if(project->values((*it) + ".CONFIG").indexOf("combine") != -1) {
+ // compilers with a combined input only have one output
+ QString input = project->values((*it) + ".output").first();
+ t << " " << escapeDependencyPath(replaceExtraCompilerVariables(tmp_out, input, QString()));
+ } else {
+ for(QStringList::ConstIterator input = tmp_inputs.begin(); input != tmp_inputs.end(); ++input) {
+ QString in = Option::fixPathToTargetOS((*input), false);
+ t << " " << escapeDependencyPath(replaceExtraCompilerVariables(tmp_out, (*input), QString()));
+ }
+ }
+ t << endl;
+
+ if(project->values((*it) + ".CONFIG").indexOf("no_clean") == -1) {
+ QString tmp_clean = project->values((*it) + ".clean").join(" ");
+ QString tmp_clean_cmds = project->values((*it) + ".clean_commands").join(" ");
+ if(!tmp_inputs.isEmpty())
+ clean_targets += QString("compiler_" + (*it) + "_clean ");
+ t << "compiler_" << (*it) << "_clean:";
+ bool wrote_clean_cmds = false, wrote_clean = false;
+ if(tmp_clean_cmds.isEmpty()) {
+ wrote_clean_cmds = true;
+ } else if(tmp_clean_cmds.indexOf("${QMAKE_") == -1) {
+ t << "\n\t" << tmp_clean_cmds;
+ wrote_clean_cmds = true;
+ }
+ if(tmp_clean.isEmpty())
+ tmp_clean = tmp_out;
+ if(tmp_clean.indexOf("${QMAKE_") == -1) {
+ t << "\n\t" << "-$(DEL_FILE) " << tmp_clean;
+ wrote_clean = true;
+ }
+ if(!wrote_clean_cmds || !wrote_clean) {
+ QStringList cleans;
+ const QString del_statement("-$(DEL_FILE)");
+ if(!wrote_clean) {
+ if(project->isActiveConfig("no_delete_multiple_files")) {
+ for(QStringList::ConstIterator input = tmp_inputs.begin(); input != tmp_inputs.end(); ++input)
+ cleans.append(" " + replaceExtraCompilerVariables(tmp_clean, (*input),
+ replaceExtraCompilerVariables(tmp_out, (*input), QString())));
+ } else {
+ QString files, file;
+ const int commandlineLimit = 2047; // NT limit, expanded
+ for(int input = 0; input < tmp_inputs.size(); ++input) {
+ file = " " + replaceExtraCompilerVariables(tmp_clean, tmp_inputs.at(input),
+ replaceExtraCompilerVariables(tmp_out, tmp_inputs.at(input), QString()));
+ if(del_statement.length() + files.length() +
+ qMax(fixEnvVariables(file).length(), file.length()) > commandlineLimit) {
+ cleans.append(files);
+ files.clear();
+ }
+ files += file;
+ }
+ if(!files.isEmpty())
+ cleans.append(files);
+ }
+ }
+ if(!cleans.isEmpty())
+ t << valGlue(cleans, "\n\t" + del_statement, "\n\t" + del_statement, "");
+ if(!wrote_clean_cmds) {
+ for(QStringList::ConstIterator input = tmp_inputs.begin(); input != tmp_inputs.end(); ++input) {
+ t << "\n\t" << replaceExtraCompilerVariables(tmp_clean_cmds, (*input),
+ replaceExtraCompilerVariables(tmp_out, (*input), QString()));
+ }
+ }
+ }
+ t << endl;
+ }
+ if(project->values((*it) + ".CONFIG").indexOf("combine") != -1) {
+ if(tmp_out.indexOf("${QMAKE_") != -1) {
+ warn_msg(WarnLogic, "QMAKE_EXTRA_COMPILERS(%s) with combine has variable output.",
+ (*it).toLatin1().constData());
+ continue;
+ }
+ QStringList deps, inputs;
+ if(!tmp_dep.isEmpty())
+ deps += fileFixify(tmp_dep, Option::output_dir, Option::output_dir);
+ for(QStringList::ConstIterator input = tmp_inputs.begin(); input != tmp_inputs.end(); ++input) {
+ deps += findDependencies((*input));
+ inputs += Option::fixPathToTargetOS((*input), false);
+ if(!tmp_dep_cmd.isEmpty() && doDepends()) {
+ char buff[256];
+ QString dep_cmd = replaceExtraCompilerVariables(tmp_dep_cmd, (*input),
+ tmp_out);
+ dep_cmd = fixEnvVariables(dep_cmd);
+ if(FILE *proc = QT_POPEN(dep_cmd.toLatin1().constData(), "r")) {
+ QString indeps;
+ while(!feof(proc)) {
+ int read_in = (int)fread(buff, 1, 255, proc);
+ if(!read_in)
+ break;
+ indeps += QByteArray(buff, read_in);
+ }
+ QT_PCLOSE(proc);
+ if(!indeps.isEmpty()) {
+ QStringList dep_cmd_deps = indeps.replace('\n', ' ').simplified().split(' ');
+ for(int i = 0; i < dep_cmd_deps.count(); ++i) {
+ QString &file = dep_cmd_deps[i];
+ if(!exists(file)) {
+ QString localFile;
+ QList<QMakeLocalFileName> depdirs = QMakeSourceFileInfo::dependencyPaths();
+ for(QList<QMakeLocalFileName>::Iterator it = depdirs.begin();
+ it != depdirs.end(); ++it) {
+ if(exists((*it).real() + Option::dir_sep + file)) {
+ localFile = (*it).local() + Option::dir_sep + file;
+ break;
+ }
+ }
+ file = localFile;
+ }
+ if(!file.isEmpty())
+ file = fileFixify(file);
+ }
+ deps += dep_cmd_deps;
+ }
+ }
+ }
+ }
+ for(int i = 0; i < inputs.size(); ) {
+ if(tmp_out == inputs.at(i))
+ inputs.removeAt(i);
+ else
+ ++i;
+ }
+ for(int i = 0; i < deps.size(); ) {
+ if(tmp_out == deps.at(i))
+ deps.removeAt(i);
+ else
+ ++i;
+ }
+ if (inputs.isEmpty())
+ continue;
+
+ QString cmd = replaceExtraCompilerVariables(tmp_cmd, escapeFilePaths(inputs), QStringList(tmp_out));
+ t << escapeDependencyPath(tmp_out) << ":";
+ // compiler.CONFIG+=explicit_dependencies means that ONLY compiler.depends gets to cause Makefile dependencies
+ if(project->values((*it) + ".CONFIG").indexOf("explicit_dependencies") != -1) {
+ t << " " << valList(escapeDependencyPaths(fileFixify(tmp_dep, Option::output_dir, Option::output_dir)));
+ } else {
+ t << " " << valList(escapeDependencyPaths(inputs)) << " " << valList(escapeDependencyPaths(deps));
+ }
+ t << "\n\t" << cmd << endl << endl;
+ continue;
+ }
+ for(QStringList::ConstIterator input = tmp_inputs.begin(); input != tmp_inputs.end(); ++input) {
+ QString in = Option::fixPathToTargetOS((*input), false);
+ QStringList deps = findDependencies((*input));
+ deps += escapeDependencyPath(in);
+ QString out = replaceExtraCompilerVariables(tmp_out, (*input), QString());
+ if(!tmp_dep.isEmpty()) {
+ QStringList pre_deps = fileFixify(tmp_dep, Option::output_dir, Option::output_dir);
+ for(int i = 0; i < pre_deps.size(); ++i)
+ deps += replaceExtraCompilerVariables(pre_deps.at(i), (*input), out);
+ }
+ QString cmd = replaceExtraCompilerVariables(tmp_cmd, (*input), out);
+ for(QStringList::ConstIterator it3 = vars.constBegin(); it3 != vars.constEnd(); ++it3)
+ cmd.replace("$(" + (*it3) + ")", "$(QMAKE_COMP_" + (*it3)+")");
+ if(!tmp_dep_cmd.isEmpty() && doDepends()) {
+ char buff[256];
+ QString dep_cmd = replaceExtraCompilerVariables(tmp_dep_cmd, (*input), out);
+ dep_cmd = fixEnvVariables(dep_cmd);
+ if(FILE *proc = QT_POPEN(dep_cmd.toLatin1().constData(), "r")) {
+ QString indeps;
+ while(!feof(proc)) {
+ int read_in = (int)fread(buff, 1, 255, proc);
+ if(!read_in)
+ break;
+ indeps += QByteArray(buff, read_in);
+ }
+ QT_PCLOSE(proc);
+ if(!indeps.isEmpty()) {
+ QStringList dep_cmd_deps = indeps.replace('\n', ' ').simplified().split(' ');
+ for(int i = 0; i < dep_cmd_deps.count(); ++i) {
+ QString &file = dep_cmd_deps[i];
+ if(!exists(file)) {
+ QString localFile;
+ QList<QMakeLocalFileName> depdirs = QMakeSourceFileInfo::dependencyPaths();
+ for(QList<QMakeLocalFileName>::Iterator it = depdirs.begin();
+ it != depdirs.end(); ++it) {
+ if(exists((*it).real() + Option::dir_sep + file)) {
+ localFile = (*it).local() + Option::dir_sep + file;
+ break;
+ }
+ }
+ file = localFile;
+ }
+ if(!file.isEmpty())
+ file = fileFixify(file);
+ }
+ deps += dep_cmd_deps;
+ }
+ }
+ //use the depend system to find includes of these included files
+ QStringList inc_deps;
+ for(int i = 0; i < deps.size(); ++i) {
+ const QString dep = deps.at(i);
+ if(QFile::exists(dep)) {
+ SourceFileType type = TYPE_UNKNOWN;
+ if(type == TYPE_UNKNOWN) {
+ for(QStringList::Iterator cit = Option::c_ext.begin();
+ cit != Option::c_ext.end(); ++cit) {
+ if(dep.endsWith((*cit))) {
+ type = TYPE_C;
+ break;
+ }
+ }
+ }
+ if(type == TYPE_UNKNOWN) {
+ for(QStringList::Iterator cppit = Option::cpp_ext.begin();
+ cppit != Option::cpp_ext.end(); ++cppit) {
+ if(dep.endsWith((*cppit))) {
+ type = TYPE_C;
+ break;
+ }
+ }
+ }
+ if(type == TYPE_UNKNOWN) {
+ for(QStringList::Iterator hit = Option::h_ext.begin();
+ type == TYPE_UNKNOWN && hit != Option::h_ext.end(); ++hit) {
+ if(dep.endsWith((*hit))) {
+ type = TYPE_C;
+ break;
+ }
+ }
+ }
+ if(type != TYPE_UNKNOWN) {
+ if(!QMakeSourceFileInfo::containsSourceFile(dep, type))
+ QMakeSourceFileInfo::addSourceFile(dep, type);
+ inc_deps += QMakeSourceFileInfo::dependencies(dep);
+ }
+ }
+ }
+ deps += inc_deps;
+ }
+ for(int i = 0; i < deps.size(); ) {
+ QString &dep = deps[i];
+ dep = Option::fixPathToTargetOS(unescapeFilePath(dep), false);
+ if(out == dep)
+ deps.removeAt(i);
+ else
+ ++i;
+ }
+ t << escapeDependencyPath(out) << ": " << valList(escapeDependencyPaths(deps)) << "\n\t"
+ << cmd << endl << endl;
+ }
+ }
+ t << "compiler_clean: " << clean_targets << endl << endl;
+}
+
+void
+MakefileGenerator::writeExtraCompilerVariables(QTextStream &t)
+{
+ bool first = true;
+ const QStringList &quc = project->values("QMAKE_EXTRA_COMPILERS");
+ for(QStringList::ConstIterator it = quc.begin(); it != quc.end(); ++it) {
+ const QStringList &vars = project->values((*it) + ".variables");
+ for(QStringList::ConstIterator varit = vars.begin(); varit != vars.end(); ++varit) {
+ if(first) {
+ t << "\n####### Custom Compiler Variables" << endl;
+ first = false;
+ }
+ t << "QMAKE_COMP_" << (*varit) << " = "
+ << valList(project->values((*varit))) << endl;
+ }
+ }
+ if(!first)
+ t << endl;
+}
+
+void
+MakefileGenerator::writeExtraVariables(QTextStream &t)
+{
+ bool first = true;
+ QMap<QString, QStringList> &vars = project->variables();
+ QStringList &exports = project->values("QMAKE_EXTRA_VARIABLES");
+ for(QMap<QString, QStringList>::Iterator it = vars.begin(); it != vars.end(); ++it) {
+ for(QStringList::Iterator exp_it = exports.begin(); exp_it != exports.end(); ++exp_it) {
+ QRegExp rx((*exp_it), Qt::CaseInsensitive, QRegExp::Wildcard);
+ if(rx.exactMatch(it.key())) {
+ if(first) {
+ t << "\n####### Custom Variables" << endl;
+ first = false;
+ }
+ t << "EXPORT_" << it.key() << " = " << it.value().join(" ") << endl;
+ }
+ }
+ }
+ if(!first)
+ t << endl;
+}
+
+bool
+MakefileGenerator::writeStubMakefile(QTextStream &t)
+{
+ t << "QMAKE = " << (project->isEmpty("QMAKE_QMAKE") ? QString("qmake") : var("QMAKE_QMAKE")) << endl;
+ QStringList &qut = project->values("QMAKE_EXTRA_TARGETS");
+ for(QStringList::ConstIterator it = qut.begin(); it != qut.end(); ++it)
+ t << *it << " ";
+ //const QString ofile = Option::fixPathToTargetOS(fileFixify(Option::output.fileName()));
+ t << "first all clean install distclean uninstall: " << "qmake" << endl
+ << "qmake_all:" << endl;
+ writeMakeQmake(t);
+ if(project->isEmpty("QMAKE_NOFORCE"))
+ t << "FORCE:" << endl << endl;
+ return true;
+}
+
+bool
+MakefileGenerator::writeMakefile(QTextStream &t)
+{
+ t << "####### Compile" << endl << endl;
+ writeObj(t, "SOURCES");
+ writeObj(t, "GENERATED_SOURCES");
+
+ t << "####### Install" << endl << endl;
+ writeInstalls(t, "INSTALLS");
+
+ if(project->isEmpty("QMAKE_NOFORCE"))
+ t << "FORCE:" << endl << endl;
+ return true;
+}
+
+QString MakefileGenerator::buildArgs(const QString &outdir)
+{
+ QString ret;
+ //special variables
+ if(!project->isEmpty("QMAKE_ABSOLUTE_SOURCE_PATH"))
+ ret += " QMAKE_ABSOLUTE_SOURCE_PATH=" + escapeFilePath(project->first("QMAKE_ABSOLUTE_SOURCE_PATH"));
+
+ //warnings
+ else if(Option::warn_level == WarnNone)
+ ret += " -Wnone";
+ else if(Option::warn_level == WarnAll)
+ ret += " -Wall";
+ else if(Option::warn_level & WarnParser)
+ ret += " -Wparser";
+ //other options
+ if(!Option::user_template.isEmpty())
+ ret += " -t " + Option::user_template;
+ if(!Option::user_template_prefix.isEmpty())
+ ret += " -tp " + Option::user_template_prefix;
+ if(!Option::mkfile::do_cache)
+ ret += " -nocache";
+ if(!Option::mkfile::do_deps)
+ ret += " -nodepend";
+ if(!Option::mkfile::do_dep_heuristics)
+ ret += " -nodependheuristics";
+ if(!Option::mkfile::qmakespec_commandline.isEmpty())
+ ret += " -spec " + specdir(outdir);
+ if(Option::target_mode == Option::TARG_MAC9_MODE)
+ ret += " -mac9";
+ else if(Option::target_mode == Option::TARG_MACX_MODE)
+ ret += " -macx";
+ else if(Option::target_mode == Option::TARG_UNIX_MODE)
+ ret += " -unix";
+ else if(Option::target_mode == Option::TARG_WIN_MODE)
+ ret += " -win32";
+ else if(Option::target_mode == Option::TARG_QNX6_MODE)
+ ret += " -qnx6";
+
+ //configs
+ for(QStringList::Iterator it = Option::user_configs.begin();
+ it != Option::user_configs.end(); ++it)
+ ret += " -config " + (*it);
+ //arguments
+ for(QStringList::Iterator it = Option::before_user_vars.begin();
+ it != Option::before_user_vars.end(); ++it) {
+ if((*it).left(qstrlen("QMAKE_ABSOLUTE_SOURCE_PATH")) != "QMAKE_ABSOLUTE_SOURCE_PATH")
+ ret += " " + escapeFilePath((*it));
+ }
+ if(Option::after_user_vars.count()) {
+ ret += " -after ";
+ for(QStringList::Iterator it = Option::after_user_vars.begin();
+ it != Option::after_user_vars.end(); ++it) {
+ if((*it).left(qstrlen("QMAKE_ABSOLUTE_SOURCE_PATH")) != "QMAKE_ABSOLUTE_SOURCE_PATH")
+ ret += " " + escapeFilePath((*it));
+ }
+ }
+ return ret;
+}
+
+//could get stored argv, but then it would have more options than are
+//probably necesary this will try to guess the bare minimum..
+QString MakefileGenerator::build_args(const QString &outdir)
+{
+ QString ret = "$(QMAKE)";
+
+ // general options and arguments
+ ret += buildArgs(outdir);
+
+ //output
+ QString ofile = Option::fixPathToTargetOS(fileFixify(Option::output.fileName()));
+ if(!ofile.isEmpty() && ofile != project->first("QMAKE_MAKEFILE"))
+ ret += " -o " + escapeFilePath(ofile);
+
+ //inputs
+ ret += " " + escapeFilePath(fileFixify(project->projectFile(), outdir));
+
+ return ret;
+}
+
+void
+MakefileGenerator::writeHeader(QTextStream &t)
+{
+ t << "#############################################################################" << endl;
+ t << "# Makefile for building: " << escapeFilePath(var("TARGET")) << endl;
+ t << "# Generated by qmake (" << qmake_version() << ") (Qt " << QT_VERSION_STR << ") on: ";
+ t << QDateTime::currentDateTime().toString() << endl;
+ t << "# Project: " << fileFixify(project->projectFile()) << endl;
+ t << "# Template: " << var("TEMPLATE") << endl;
+ if(!project->isActiveConfig("build_pass"))
+ t << "# Command: " << build_args().replace("$(QMAKE)",
+ (project->isEmpty("QMAKE_QMAKE") ? QString("qmake") : var("QMAKE_QMAKE"))) << endl;
+ t << "#############################################################################" << endl;
+ t << endl;
+}
+
+void
+MakefileGenerator::writeSubDirs(QTextStream &t)
+{
+ QList<SubTarget*> targets;
+ {
+ const QStringList subdirs = project->values("SUBDIRS");
+ for(int subdir = 0; subdir < subdirs.size(); ++subdir) {
+ QString fixedSubdir = subdirs[subdir];
+ fixedSubdir = fixedSubdir.replace(QRegExp("[^a-zA-Z0-9_]"),"-");
+
+ SubTarget *st = new SubTarget;
+ st->name = subdirs[subdir];
+ targets.append(st);
+
+ bool fromFile = false;
+ QString file = subdirs[subdir];
+ if(!project->isEmpty(fixedSubdir + ".file")) {
+ if(!project->isEmpty(fixedSubdir + ".subdir"))
+ warn_msg(WarnLogic, "Cannot assign both file and subdir for subdir %s",
+ subdirs[subdir].toLatin1().constData());
+ file = project->first(fixedSubdir + ".file");
+ fromFile = true;
+ } else if(!project->isEmpty(fixedSubdir + ".subdir")) {
+ file = project->first(fixedSubdir + ".subdir");
+ fromFile = false;
+ } else {
+ fromFile = file.endsWith(Option::pro_ext);
+ }
+ file = Option::fixPathToTargetOS(file);
+
+ if(fromFile) {
+ int slsh = file.lastIndexOf(Option::dir_sep);
+ if(slsh != -1) {
+ st->in_directory = file.left(slsh+1);
+ st->profile = file.mid(slsh+1);
+ } else {
+ st->profile = file;
+ }
+ } else {
+ if(!file.isEmpty() && !project->isActiveConfig("subdir_first_pro"))
+ st->profile = file.section(Option::dir_sep, -1) + Option::pro_ext;
+ st->in_directory = file;
+ }
+ while(st->in_directory.right(1) == Option::dir_sep)
+ st->in_directory = st->in_directory.left(st->in_directory.length() - 1);
+ if(fileInfo(st->in_directory).isRelative())
+ st->out_directory = st->in_directory;
+ else
+ st->out_directory = fileFixify(st->in_directory, qmake_getpwd(), Option::output_dir);
+ if(!project->isEmpty(fixedSubdir + ".makefile")) {
+ st->makefile = project->first(fixedSubdir + ".makefile");
+ } else {
+ st->makefile = "$(MAKEFILE)";
+ if(!st->profile.isEmpty()) {
+ QString basename = st->in_directory;
+ int new_slsh = basename.lastIndexOf(Option::dir_sep);
+ if(new_slsh != -1)
+ basename = basename.mid(new_slsh+1);
+ if(st->profile != basename + Option::pro_ext)
+ st->makefile += "." + st->profile.left(st->profile.length() - Option::pro_ext.length());
+ }
+ }
+ if(!project->isEmpty(fixedSubdir + ".depends")) {
+ const QStringList depends = project->values(fixedSubdir + ".depends");
+ for(int depend = 0; depend < depends.size(); ++depend) {
+ bool found = false;
+ for(int subDep = 0; subDep < subdirs.size(); ++subDep) {
+ if(subdirs[subDep] == depends.at(depend)) {
+ QString fixedSubDep = subdirs[subDep];
+ fixedSubDep = fixedSubDep.replace(QRegExp("[^a-zA-Z0-9_]"),"-");
+ if(!project->isEmpty(fixedSubDep + ".target")) {
+ st->depends += project->first(fixedSubDep + ".target");
+ } else {
+ QString d = Option::fixPathToLocalOS(subdirs[subDep]);
+ if(!project->isEmpty(fixedSubDep + ".file"))
+ d = project->first(fixedSubDep + ".file");
+ else if(!project->isEmpty(fixedSubDep + ".subdir"))
+ d = project->first(fixedSubDep + ".subdir");
+ st->depends += "sub-" + d.replace(QRegExp("[^a-zA-Z0-9_]"),"-");
+ }
+ found = true;
+ break;
+ }
+ }
+ if(!found) {
+ QString depend_str = depends.at(depend);
+ st->depends += depend_str.replace(QRegExp("[^a-zA-Z0-9_]"),"-");
+ }
+ }
+ }
+ if(!project->isEmpty(fixedSubdir + ".target")) {
+ st->target = project->first(fixedSubdir + ".target");
+ } else {
+ st->target = "sub-" + file;
+ st->target = st->target.replace(QRegExp("[^a-zA-Z0-9_]"),"-");
+ }
+ }
+ }
+ t << "first: make_default" << endl;
+ int flags = SubTargetInstalls;
+ if(project->isActiveConfig("ordered"))
+ flags |= SubTargetOrdered;
+ writeSubTargets(t, targets, flags);
+ qDeleteAll(targets);
+}
+
+void
+MakefileGenerator::writeSubTargets(QTextStream &t, QList<MakefileGenerator::SubTarget*> targets, int flags)
+{
+ // blasted includes
+ QStringList &qeui = project->values("QMAKE_EXTRA_INCLUDES");
+ for(QStringList::Iterator qeui_it = qeui.begin(); qeui_it != qeui.end(); ++qeui_it)
+ t << "include " << (*qeui_it) << endl;
+
+ QString ofile = Option::fixPathToTargetOS(Option::output.fileName());
+ if(ofile.lastIndexOf(Option::dir_sep) != -1)
+ ofile = ofile.right(ofile.length() - ofile.lastIndexOf(Option::dir_sep) -1);
+ t << "MAKEFILE = " << ofile << endl;
+ /* Calling Option::fixPathToTargetOS() is necessary for MinGW/MSYS, which requires
+ * back-slashes to be turned into slashes. */
+ t << "QMAKE = " << Option::fixPathToTargetOS(var("QMAKE_QMAKE")) << endl;
+ t << "DEL_FILE = " << var("QMAKE_DEL_FILE") << endl;
+ t << "CHK_DIR_EXISTS= " << var("QMAKE_CHK_DIR_EXISTS") << endl;
+ t << "MKDIR = " << var("QMAKE_MKDIR") << endl;
+ t << "COPY = " << var("QMAKE_COPY") << endl;
+ t << "COPY_FILE = " << var("QMAKE_COPY_FILE") << endl;
+ t << "COPY_DIR = " << var("QMAKE_COPY_DIR") << endl;
+ t << "INSTALL_FILE = " << var("QMAKE_INSTALL_FILE") << endl;
+ t << "INSTALL_PROGRAM = " << var("QMAKE_INSTALL_PROGRAM") << endl;
+ t << "INSTALL_DIR = " << var("QMAKE_INSTALL_DIR") << endl;
+ t << "DEL_FILE = " << var("QMAKE_DEL_FILE") << endl;
+ t << "SYMLINK = " << var("QMAKE_SYMBOLIC_LINK") << endl;
+ t << "DEL_DIR = " << var("QMAKE_DEL_DIR") << endl;
+ t << "MOVE = " << var("QMAKE_MOVE") << endl;
+ t << "CHK_DIR_EXISTS= " << var("QMAKE_CHK_DIR_EXISTS") << endl;
+ t << "MKDIR = " << var("QMAKE_MKDIR") << endl;
+ writeExtraVariables(t);
+ t << "SUBTARGETS = "; // subtargets are sub-directory
+ for(int target = 0; target < targets.size(); ++target)
+ t << " \\\n\t\t" << targets.at(target)->target;
+ t << endl << endl;
+
+ QStringList targetSuffixes;
+ const QString abs_source_path = project->first("QMAKE_ABSOLUTE_SOURCE_PATH");
+ targetSuffixes << "make_default" << "make_first" << "all" << "clean" << "distclean"
+ << QString((flags & SubTargetInstalls) ? "install_subtargets" : "install")
+ << QString((flags & SubTargetInstalls) ? "uninstall_subtargets" : "uninstall");
+
+ // generate target rules
+ for(int target = 0; target < targets.size(); ++target) {
+ SubTarget *subtarget = targets.at(target);
+ QString in_directory = subtarget->in_directory;
+ if(!in_directory.isEmpty() && !in_directory.endsWith(Option::dir_sep))
+ in_directory += Option::dir_sep;
+ QString out_directory = subtarget->out_directory;
+ if(!out_directory.isEmpty() && !out_directory.endsWith(Option::dir_sep))
+ out_directory += Option::dir_sep;
+ if(!abs_source_path.isEmpty() && out_directory.startsWith(abs_source_path))
+ out_directory = Option::output_dir + out_directory.mid(abs_source_path.length());
+
+ QString mkfile = subtarget->makefile;
+ if(!in_directory.isEmpty())
+ mkfile.prepend(out_directory);
+
+ QString in_directory_cdin, in_directory_cdout, out_directory_cdin, out_directory_cdout;
+#define MAKE_CD_IN_AND_OUT(directory) \
+ if(!directory.isEmpty()) { \
+ if(project->isActiveConfig("cd_change_global")) { \
+ directory ## _cdin = "\n\tcd " + directory + "\n\t"; \
+ QDir pwd(Option::output_dir); \
+ QStringList in = directory.split(Option::dir_sep), out; \
+ for(int i = 0; i < in.size(); i++) { \
+ if(in.at(i) == "..") \
+ out.prepend(fileInfo(pwd.path()).fileName()); \
+ else if(in.at(i) != ".") \
+ out.prepend(".."); \
+ pwd.cd(in.at(i)); \
+ } \
+ directory ## _cdout = "\n\t@cd " + out.join(Option::dir_sep); \
+ } else { \
+ directory ## _cdin = "\n\tcd " + directory + " && "; \
+ } \
+ } else { \
+ directory ## _cdin = "\n\t"; \
+ }
+ MAKE_CD_IN_AND_OUT(in_directory);
+ MAKE_CD_IN_AND_OUT(out_directory);
+
+ //qmake it
+ if(!subtarget->profile.isEmpty()) {
+ QString out = out_directory + subtarget->makefile,
+ in = fileFixify(in_directory + subtarget->profile, in_directory);
+ if(in.startsWith(in_directory))
+ in = in.mid(in_directory.length());
+ if(out.startsWith(in_directory))
+ out = out.mid(in_directory.length());
+ t << mkfile << ": " << "\n\t";
+ if(!in_directory.isEmpty()) {
+ t << mkdir_p_asstring(in_directory)
+ << in_directory_cdin
+ << "$(QMAKE) " << in << buildArgs(in_directory) << " -o " << out
+ << in_directory_cdout << endl;
+ } else {
+ t << "$(QMAKE) " << in << buildArgs(in_directory) << " -o " << out << endl;
+ }
+ t << subtarget->target << "-qmake_all: ";
+ if(project->isEmpty("QMAKE_NOFORCE"))
+ t << " FORCE";
+ t << "\n\t";
+ if(!in_directory.isEmpty()) {
+ t << mkdir_p_asstring(in_directory)
+ << in_directory_cdin
+ << "$(QMAKE) " << in << buildArgs(in_directory) << " -o " << out
+ << in_directory_cdout << endl;
+ } else {
+ t << "$(QMAKE) " << in << buildArgs(in_directory) << " -o " << out << endl;
+ }
+ }
+
+ QString makefilein = " -f " + subtarget->makefile;
+
+ { //actually compile
+ t << subtarget->target << ": " << mkfile;
+ if(!subtarget->depends.isEmpty())
+ t << " " << valList(subtarget->depends);
+ if(project->isEmpty("QMAKE_NOFORCE"))
+ t << " FORCE";
+ t << out_directory_cdin
+ << "$(MAKE)" << makefilein
+ << out_directory_cdout << endl;
+ }
+
+ for(int suffix = 0; suffix < targetSuffixes.size(); ++suffix) {
+ QString s = targetSuffixes.at(suffix);
+ if(s == "install_subtargets")
+ s = "install";
+ else if(s == "uninstall_subtargets")
+ s = "uninstall";
+ else if(s == "make_first")
+ s = "first";
+ else if(s == "make_default")
+ s = QString();
+
+ if(flags & SubTargetOrdered) {
+ t << subtarget->target << "-" << targetSuffixes.at(suffix) << "-ordered: " << mkfile;
+ if(target)
+ t << " " << targets.at(target-1)->target << "-" << targetSuffixes.at(suffix) << "-ordered ";
+ if(project->isEmpty("QMAKE_NOFORCE"))
+ t << " FORCE";
+ t << out_directory_cdin
+ << "$(MAKE)" << makefilein << " " << s
+ << out_directory_cdout << endl;
+ }
+ t << subtarget->target << "-" << targetSuffixes.at(suffix) << ": " << mkfile;
+ if(!subtarget->depends.isEmpty())
+ t << " " << valGlue(subtarget->depends, QString(), "-" + targetSuffixes.at(suffix) + " ",
+ "-"+targetSuffixes.at(suffix));
+ if(project->isEmpty("QMAKE_NOFORCE"))
+ t << " FORCE";
+ t << out_directory_cdin
+ << "$(MAKE)" << makefilein << " " << s
+ << out_directory_cdout << endl;
+ }
+ }
+ t << endl;
+
+ if(project->values("QMAKE_INTERNAL_QMAKE_DEPS").indexOf("qmake_all") == -1)
+ project->values("QMAKE_INTERNAL_QMAKE_DEPS").append("qmake_all");
+
+ writeMakeQmake(t);
+
+ t << "qmake_all:";
+ if(!targets.isEmpty()) {
+ for(QList<SubTarget*>::Iterator it = targets.begin(); it != targets.end(); ++it) {
+ if(!(*it)->profile.isEmpty())
+ t << " " << (*it)->target << "-" << "qmake_all";
+ }
+ }
+ if(project->isEmpty("QMAKE_NOFORCE"))
+ t << " FORCE";
+ if(project->isActiveConfig("no_empty_targets"))
+ t << "\n\t" << "@cd .";
+ t << endl << endl;
+
+ for(int s = 0; s < targetSuffixes.size(); ++s) {
+ QString suffix = targetSuffixes.at(s);
+ if(!(flags & SubTargetInstalls) && suffix.endsWith("install"))
+ continue;
+
+ t << suffix << ":";
+ for(int target = 0; target < targets.size(); ++target) {
+ QString targetRule = targets.at(target)->target + "-" + suffix;
+ if(flags & SubTargetOrdered)
+ targetRule += "-ordered";
+ t << " " << targetRule;
+ }
+ if(suffix == "all" || suffix == "make_first")
+ t << varGlue("ALL_DEPS"," "," ","");
+ if(suffix == "clean")
+ t << varGlue("CLEAN_DEPS"," "," ","");
+ if(project->isEmpty("QMAKE_NOFORCE"))
+ t << " FORCE";
+ t << endl;
+ if(suffix == "clean") {
+ t << varGlue("QMAKE_CLEAN","\t-$(DEL_FILE) ","\n\t-$(DEL_FILE) ", "\n");
+ } else if(suffix == "distclean") {
+ QString ofile = Option::fixPathToTargetOS(fileFixify(Option::output.fileName()));
+ if(!ofile.isEmpty())
+ t << "\t-$(DEL_FILE) " << ofile << endl;
+ } else if(project->isActiveConfig("no_empty_targets")) {
+ t << "\t" << "@cd ." << endl;
+ }
+ }
+
+ // user defined targets
+ QStringList &qut = project->values("QMAKE_EXTRA_TARGETS");
+ for(QStringList::Iterator qut_it = qut.begin(); qut_it != qut.end(); ++qut_it) {
+ QString targ = var((*qut_it) + ".target"),
+ cmd = var((*qut_it) + ".commands"), deps;
+ if(targ.isEmpty())
+ targ = (*qut_it);
+ t << endl;
+
+ QStringList &deplist = project->values((*qut_it) + ".depends");
+ for(QStringList::Iterator dep_it = deplist.begin(); dep_it != deplist.end(); ++dep_it) {
+ QString dep = var((*dep_it) + ".target");
+ if(dep.isEmpty())
+ dep = Option::fixPathToTargetOS(*dep_it, false);
+ deps += " " + dep;
+ }
+ if(project->values((*qut_it) + ".CONFIG").indexOf("recursive") != -1) {
+ QSet<QString> recurse;
+ if(project->isSet((*qut_it) + ".recurse")) {
+ recurse = project->values((*qut_it) + ".recurse").toSet();
+ } else {
+ for(int target = 0; target < targets.size(); ++target)
+ recurse.insert(targets.at(target)->name);
+ }
+ for(int target = 0; target < targets.size(); ++target) {
+ SubTarget *subtarget = targets.at(target);
+ QString in_directory = subtarget->in_directory;
+ if(!in_directory.isEmpty() && !in_directory.endsWith(Option::dir_sep))
+ in_directory += Option::dir_sep;
+ QString out_directory = subtarget->out_directory;
+ if(!out_directory.isEmpty() && !out_directory.endsWith(Option::dir_sep))
+ out_directory += Option::dir_sep;
+ if(!abs_source_path.isEmpty() && out_directory.startsWith(abs_source_path))
+ out_directory = Option::output_dir + out_directory.mid(abs_source_path.length());
+
+ if(!recurse.contains(subtarget->name))
+ continue;
+ QString mkfile = subtarget->makefile;
+ if(!in_directory.isEmpty()) {
+ if(!out_directory.endsWith(Option::dir_sep))
+ mkfile.prepend(out_directory + Option::dir_sep);
+ else
+ mkfile.prepend(out_directory);
+ }
+ QString out_directory_cdin, out_directory_cdout;
+ MAKE_CD_IN_AND_OUT(out_directory);
+
+ //don't need the makefile arg if it isn't changed
+ QString makefilein;
+ if(subtarget->makefile != "$(MAKEFILE)")
+ makefilein = " -f " + subtarget->makefile;
+
+ //write the rule/depends
+ if(flags & SubTargetOrdered) {
+ const QString dep = subtarget->target + "-" + (*qut_it) + "_ordered";
+ t << dep << ": " << mkfile;
+ if(target)
+ t << " " << targets.at(target-1)->target << "-" << (*qut_it) << "_ordered ";
+ deps += " " + dep;
+ } else {
+ const QString dep = subtarget->target + "-" + (*qut_it);
+ t << dep << ": " << mkfile;
+ if(!subtarget->depends.isEmpty())
+ t << " " << valGlue(subtarget->depends, QString(), "-" + (*qut_it) + " ", "-" + (*qut_it));
+ deps += " " + dep;
+ }
+
+ QString sub_targ = targ;
+ if(project->isSet((*qut_it) + ".recurse_target"))
+ sub_targ = project->first((*qut_it) + ".recurse_target");
+
+ //write the commands
+ if(!out_directory.isEmpty()) {
+ t << out_directory_cdin
+ << "$(MAKE)" << makefilein << " " << sub_targ
+ << out_directory_cdout << endl;
+ } else {
+ t << "\n\t"
+ << "$(MAKE)" << makefilein << " " << sub_targ << endl;
+ }
+ }
+ }
+ if(project->isEmpty("QMAKE_NOFORCE") &&
+ project->values((*qut_it) + ".CONFIG").indexOf("phony") != -1)
+ deps += " FORCE";
+ t << targ << ":" << deps << "\n";
+ if(!cmd.isEmpty())
+ t << "\t" << cmd << endl;
+ }
+
+ if(flags & SubTargetInstalls) {
+ project->values("INSTALLDEPS") += "install_subtargets";
+ project->values("UNINSTALLDEPS") += "uninstall_subtargets";
+ writeInstalls(t, "INSTALLS", true);
+ }
+
+ if(project->isEmpty("QMAKE_NOFORCE"))
+ t << "FORCE:" << endl << endl;
+}
+
+void
+MakefileGenerator::writeMakeQmake(QTextStream &t)
+{
+ QString ofile = Option::fixPathToTargetOS(fileFixify(Option::output.fileName()));
+ if(project->isEmpty("QMAKE_FAILED_REQUIREMENTS") && !project->isEmpty("QMAKE_INTERNAL_PRL_FILE")) {
+ QStringList files = fileFixify(Option::mkfile::project_files);
+ t << escapeDependencyPath(project->first("QMAKE_INTERNAL_PRL_FILE")) << ": " << "\n\t"
+ << "@$(QMAKE) -prl " << buildArgs() << " " << files.join(" ") << endl;
+ }
+
+ QString pfile = project->projectFile();
+ if(pfile != "(stdin)") {
+ QString qmake = build_args();
+ if(!ofile.isEmpty() && !project->isActiveConfig("no_autoqmake")) {
+ t << escapeFilePath(ofile) << ": " << escapeDependencyPath(fileFixify(pfile)) << " ";
+ if(Option::mkfile::do_cache)
+ t << escapeDependencyPath(fileFixify(Option::mkfile::cachefile)) << " ";
+ if(!specdir().isEmpty()) {
+ if(exists(Option::fixPathToLocalOS(specdir()+QDir::separator()+"qmake.conf")))
+ t << escapeDependencyPath(specdir() + Option::dir_sep + "qmake.conf") << " ";
+ else if(exists(Option::fixPathToLocalOS(specdir()+QDir::separator()+"tmake.conf")))
+ t << escapeDependencyPath(specdir() + Option::dir_sep + "tmake.conf") << " ";
+ }
+ const QStringList &included = project->values("QMAKE_INTERNAL_INCLUDED_FILES");
+ t << escapeDependencyPaths(included).join(" \\\n\t\t") << "\n\t"
+ << qmake << endl;
+ for(int include = 0; include < included.size(); ++include) {
+ const QString i(included.at(include));
+ if(!i.isEmpty())
+ t << i << ":" << endl;
+ }
+ }
+ if(project->first("QMAKE_ORIG_TARGET") != "qmake") {
+ t << "qmake: " <<
+ project->values("QMAKE_INTERNAL_QMAKE_DEPS").join(" \\\n\t\t");
+ if(project->isEmpty("QMAKE_NOFORCE"))
+ t << " FORCE";
+ t << "\n\t" << "@" << qmake << endl << endl;
+ }
+ }
+}
+
+QFileInfo
+MakefileGenerator::fileInfo(QString file) const
+{
+ static QHash<FileInfoCacheKey, QFileInfo> *cache = 0;
+ static QFileInfo noInfo = QFileInfo();
+ if(!cache) {
+ cache = new QHash<FileInfoCacheKey, QFileInfo>;
+ qmakeAddCacheClear(qmakeDeleteCacheClear_QHashFileInfoCacheKeyQFileInfo, (void**)&cache);
+ }
+ FileInfoCacheKey cacheKey(file);
+ QFileInfo value = cache->value(cacheKey, noInfo);
+ if (value != noInfo)
+ return value;
+
+ QFileInfo fi(file);
+ if (fi.exists())
+ cache->insert(cacheKey, fi);
+ return fi;
+}
+
+QString
+MakefileGenerator::unescapeFilePath(const QString &path) const
+{
+ QString ret = path;
+ if(!ret.isEmpty()) {
+ if(ret.contains(QLatin1String("\\ ")))
+ ret.replace(QLatin1String("\\ "), QLatin1String(" "));
+ if(ret.contains(QLatin1Char('\"')))
+ ret.remove(QLatin1Char('\"'));
+ }
+ return ret;
+}
+
+QStringList
+MakefileGenerator::escapeFilePaths(const QStringList &paths) const
+{
+ QStringList ret;
+ for(int i = 0; i < paths.size(); ++i)
+ ret.append(escapeFilePath(paths.at(i)));
+ return ret;
+}
+
+QStringList
+MakefileGenerator::escapeDependencyPaths(const QStringList &paths) const
+{
+ QStringList ret;
+ for(int i = 0; i < paths.size(); ++i)
+ ret.append(escapeDependencyPath(paths.at(i)));
+ return ret;
+}
+
+QStringList
+MakefileGenerator::unescapeFilePaths(const QStringList &paths) const
+{
+ QStringList ret;
+ for(int i = 0; i < paths.size(); ++i)
+ ret.append(unescapeFilePath(paths.at(i)));
+ return ret;
+}
+
+QStringList
+MakefileGenerator::fileFixify(const QStringList& files, const QString &out_dir, const QString &in_dir,
+ FileFixifyType fix, bool canon) const
+{
+ if(files.isEmpty())
+ return files;
+ QStringList ret;
+ for(QStringList::ConstIterator it = files.begin(); it != files.end(); ++it) {
+ if(!(*it).isEmpty())
+ ret << fileFixify((*it), out_dir, in_dir, fix, canon);
+ }
+ return ret;
+}
+
+QString
+MakefileGenerator::fileFixify(const QString& file, const QString &out_d, const QString &in_d,
+ FileFixifyType fix, bool canon) const
+{
+ if(file.isEmpty())
+ return file;
+ QString ret = unescapeFilePath(file);
+
+ //setup the cache
+ static QHash<FileFixifyCacheKey, QString> *cache = 0;
+ if(!cache) {
+ cache = new QHash<FileFixifyCacheKey, QString>;
+ qmakeAddCacheClear(qmakeDeleteCacheClear_QHashFileFixifyCacheKeyQString, (void**)&cache);
+ }
+ FileFixifyCacheKey cacheKey(ret, out_d, in_d, fix, canon);
+ QString cacheVal = cache->value(cacheKey);
+ if(!cacheVal.isNull())
+ return cacheVal;
+
+ //do the fixin'
+ const QString pwd = qmake_getpwd() + "/";
+ QString orig_file = ret;
+ if(ret.startsWith(QLatin1Char('~'))) {
+ if(ret.startsWith(QLatin1String("~/")))
+ ret = QDir::homePath() + Option::dir_sep + ret.mid(1);
+ else
+ warn_msg(WarnLogic, "Unable to expand ~ in %s", ret.toLatin1().constData());
+ }
+ if(fix == FileFixifyAbsolute || (fix == FileFixifyDefault && project->isActiveConfig("no_fixpath"))) {
+ if(fix == FileFixifyAbsolute && QDir::isRelativePath(ret)) //already absolute
+ ret.prepend(pwd);
+ ret = Option::fixPathToTargetOS(ret, false, canon);
+ } else { //fix it..
+ QString qfile(Option::fixPathToLocalOS(ret, true, canon)), in_dir(in_d), out_dir(out_d);
+ {
+ if(out_dir.isNull() || QDir::isRelativePath(out_dir))
+ out_dir.prepend(Option::output_dir + "/");
+ else if(out_dir == ".")
+ out_dir = pwd;
+ if(in_dir.isEmpty() || QDir::isRelativePath(in_dir))
+ in_dir.prepend(pwd);
+ else if(in_dir == ".")
+ in_dir = pwd;
+ QFileInfo in_fi(fileInfo(in_dir));
+ if(in_fi.exists())
+ in_dir = in_fi.canonicalFilePath();
+ QFileInfo out_fi(fileInfo(out_dir));
+ if(out_fi.exists())
+ out_dir = out_fi.canonicalFilePath();
+ }
+
+ QFileInfo qfileinfo(fileInfo(qfile));
+ if(out_dir != in_dir || !qfileinfo.isRelative()) {
+ if(qfileinfo.isRelative()) {
+ ret = in_dir + "/" + qfile;
+ qfileinfo.setFile(ret);
+ }
+ ret = Option::fixPathToTargetOS(ret, false, canon);
+ if(canon && qfileinfo.exists() &&
+ file == Option::fixPathToTargetOS(ret, true, canon))
+ ret = Option::fixPathToTargetOS(qfileinfo.canonicalFilePath());
+ QString match_dir = Option::fixPathToTargetOS(out_dir, false, canon);
+ if(ret == match_dir) {
+ ret = "";
+ } else if(ret.startsWith(match_dir + Option::dir_sep)) {
+ ret = ret.mid(match_dir.length() + Option::dir_sep.length());
+ } else {
+ //figure out the depth
+ int depth = 4;
+ if(Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE ||
+ Option::qmake_mode == Option::QMAKE_GENERATE_PRL) {
+ if(project && !project->isEmpty("QMAKE_PROJECT_DEPTH"))
+ depth = project->first("QMAKE_PROJECT_DEPTH").toInt();
+ else if(Option::mkfile::cachefile_depth != -1)
+ depth = Option::mkfile::cachefile_depth;
+ }
+ //calculate how much can be removed
+ QString dot_prefix;
+ for(int i = 1; i <= depth; i++) {
+ int sl = match_dir.lastIndexOf(Option::dir_sep);
+ if(sl == -1)
+ break;
+ match_dir = match_dir.left(sl);
+ if(match_dir.isEmpty())
+ break;
+ if(ret.startsWith(match_dir + Option::dir_sep)) {
+ //concat
+ int remlen = ret.length() - (match_dir.length() + 1);
+ if(remlen < 0)
+ remlen = 0;
+ ret = ret.right(remlen);
+ //prepend
+ for(int o = 0; o < i; o++)
+ dot_prefix += ".." + Option::dir_sep;
+ }
+ }
+ ret.prepend(dot_prefix);
+ }
+ } else {
+ ret = Option::fixPathToTargetOS(ret, false, canon);
+ }
+ }
+ if(ret.isEmpty())
+ ret = ".";
+ debug_msg(3, "Fixed[%d] %s :: to :: %s [%s::%s] [%s::%s]", fix, orig_file.toLatin1().constData(),
+ ret.toLatin1().constData(), in_d.toLatin1().constData(), out_d.toLatin1().constData(),
+ pwd.toLatin1().constData(), Option::output_dir.toLatin1().constData());
+ cache->insert(cacheKey, ret);
+ return ret;
+}
+
+void
+MakefileGenerator::checkMultipleDefinition(const QString &f, const QString &w)
+{
+ if(!(Option::warn_level & WarnLogic))
+ return;
+ QString file = f;
+ int slsh = f.lastIndexOf(Option::dir_sep);
+ if(slsh != -1)
+ file = file.right(file.length() - slsh - 1);
+ QStringList &l = project->values(w);
+ for(QStringList::Iterator val_it = l.begin(); val_it != l.end(); ++val_it) {
+ QString file2((*val_it));
+ slsh = file2.lastIndexOf(Option::dir_sep);
+ if(slsh != -1)
+ file2 = file2.right(file2.length() - slsh - 1);
+ if(file2 == file) {
+ warn_msg(WarnLogic, "Found potential symbol conflict of %s (%s) in %s",
+ file.toLatin1().constData(), (*val_it).toLatin1().constData(), w.toLatin1().constData());
+ break;
+ }
+ }
+}
+
+QMakeLocalFileName
+MakefileGenerator::fixPathForFile(const QMakeLocalFileName &file, bool forOpen)
+{
+ if(forOpen)
+ return QMakeLocalFileName(fileFixify(file.real(), qmake_getpwd(), Option::output_dir));
+ return QMakeLocalFileName(fileFixify(file.real()));
+}
+
+QFileInfo
+MakefileGenerator::findFileInfo(const QMakeLocalFileName &file)
+{
+ return fileInfo(file.local());
+}
+
+QMakeLocalFileName
+MakefileGenerator::findFileForDep(const QMakeLocalFileName &dep, const QMakeLocalFileName &file)
+{
+ QMakeLocalFileName ret;
+ if(!project->isEmpty("SKIP_DEPENDS")) {
+ bool found = false;
+ QStringList &nodeplist = project->values("SKIP_DEPENDS");
+ for(QStringList::Iterator it = nodeplist.begin();
+ it != nodeplist.end(); ++it) {
+ QRegExp regx((*it));
+ if(regx.indexIn(dep.local()) != -1) {
+ found = true;
+ break;
+ }
+ }
+ if(found)
+ return ret;
+ }
+
+ ret = QMakeSourceFileInfo::findFileForDep(dep, file);
+ if(!ret.isNull())
+ return ret;
+
+ //these are some "hacky" heuristics it will try to do on an include
+ //however these can be turned off at runtime, I'm not sure how
+ //reliable these will be, most likely when problems arise turn it off
+ //and see if they go away..
+ if(Option::mkfile::do_dep_heuristics) {
+ if(depHeuristicsCache.contains(dep.real()))
+ return depHeuristicsCache[dep.real()];
+
+ if(Option::output_dir != qmake_getpwd()
+ && QDir::isRelativePath(dep.real())) { //is it from the shadow tree
+ QList<QMakeLocalFileName> depdirs = QMakeSourceFileInfo::dependencyPaths();
+ depdirs.prepend(fileInfo(file.real()).absoluteDir().path());
+ QString pwd = qmake_getpwd();
+ if(pwd.at(pwd.length()-1) != '/')
+ pwd += '/';
+ for(int i = 0; i < depdirs.count(); i++) {
+ QString dir = depdirs.at(i).real();
+ if(!QDir::isRelativePath(dir) && dir.startsWith(pwd))
+ dir = dir.mid(pwd.length());
+ if(QDir::isRelativePath(dir)) {
+ if(!dir.endsWith(Option::dir_sep))
+ dir += Option::dir_sep;
+ QString shadow = fileFixify(dir + dep.local(), pwd, Option::output_dir);
+ if(exists(shadow)) {
+ ret = QMakeLocalFileName(shadow);
+ goto found_dep_from_heuristic;
+ }
+ }
+ }
+ }
+ { //is it from an EXTRA_TARGET
+ const QString dep_basename = dep.local().section(Option::dir_sep, -1);
+ QStringList &qut = project->values("QMAKE_EXTRA_TARGETS");
+ for(QStringList::Iterator it = qut.begin(); it != qut.end(); ++it) {
+ QString targ = var((*it) + ".target");
+ if(targ.isEmpty())
+ targ = (*it);
+ QString out = Option::fixPathToTargetOS(targ);
+ if(out == dep.real() || out.section(Option::dir_sep, -1) == dep_basename) {
+ ret = QMakeLocalFileName(out);
+ goto found_dep_from_heuristic;
+ }
+ }
+ }
+ { //is it from an EXTRA_COMPILER
+ const QString dep_basename = dep.local().section(Option::dir_sep, -1);
+ const QStringList &quc = project->values("QMAKE_EXTRA_COMPILERS");
+ for(QStringList::ConstIterator it = quc.begin(); it != quc.end(); ++it) {
+ QString tmp_out = project->values((*it) + ".output").first();
+ if(tmp_out.isEmpty())
+ continue;
+ QStringList &tmp = project->values((*it) + ".input");
+ for(QStringList::Iterator it2 = tmp.begin(); it2 != tmp.end(); ++it2) {
+ QStringList &inputs = project->values((*it2));
+ for(QStringList::Iterator input = inputs.begin(); input != inputs.end(); ++input) {
+ QString out = Option::fixPathToTargetOS(unescapeFilePath(replaceExtraCompilerVariables(tmp_out, (*input), QString())));
+ if(out == dep.real() || out.section(Option::dir_sep, -1) == dep_basename) {
+ ret = QMakeLocalFileName(fileFixify(out, qmake_getpwd(), Option::output_dir));
+ goto found_dep_from_heuristic;
+ }
+ }
+ }
+ }
+ }
+ found_dep_from_heuristic:
+ depHeuristicsCache.insert(dep.real(), ret);
+ }
+ return ret;
+}
+
+QStringList
+&MakefileGenerator::findDependencies(const QString &file)
+{
+ const QString fixedFile = fileFixify(file);
+ if(!dependsCache.contains(fixedFile)) {
+#if 1
+ QStringList deps = QMakeSourceFileInfo::dependencies(file);
+ if(file != fixedFile)
+ deps += QMakeSourceFileInfo::dependencies(fixedFile);
+#else
+ QStringList deps = QMakeSourceFileInfo::dependencies(fixedFile);
+#endif
+ dependsCache.insert(fixedFile, deps);
+ }
+ return dependsCache[fixedFile];
+}
+
+QString
+MakefileGenerator::specdir(const QString &outdir)
+{
+#if 0
+ if(!spec.isEmpty())
+ return spec;
+#endif
+ spec = fileFixify(Option::mkfile::qmakespec, outdir);
+ return spec;
+}
+
+bool
+MakefileGenerator::openOutput(QFile &file, const QString &build) const
+{
+ {
+ QString outdir;
+ if(!file.fileName().isEmpty()) {
+ if(QDir::isRelativePath(file.fileName()))
+ file.setFileName(Option::output_dir + "/" + file.fileName()); //pwd when qmake was run
+ QFileInfo fi(fileInfo(file.fileName()));
+ if(fi.isDir())
+ outdir = file.fileName() + QDir::separator();
+ }
+ if(!outdir.isEmpty() || file.fileName().isEmpty()) {
+ QString fname = "Makefile";
+ if(!project->isEmpty("MAKEFILE"))
+ fname = project->first("MAKEFILE");
+ file.setFileName(outdir + fname);
+ }
+ }
+ if(QDir::isRelativePath(file.fileName())) {
+ QString fname = Option::output_dir; //pwd when qmake was run
+ if(!fname.endsWith("/"))
+ fname += "/";
+ fname += file.fileName();
+ file.setFileName(fname);
+ }
+ if(!build.isEmpty())
+ file.setFileName(file.fileName() + "." + build);
+ if(project->isEmpty("QMAKE_MAKEFILE"))
+ project->values("QMAKE_MAKEFILE").append(file.fileName());
+ int slsh = file.fileName().lastIndexOf(Option::dir_sep);
+ if(slsh != -1)
+ mkdir(file.fileName().left(slsh));
+ if(file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) {
+ QFileInfo fi(fileInfo(Option::output.fileName()));
+ QString od;
+ if(fi.isSymLink())
+ od = fileInfo(fi.readLink()).absolutePath();
+ else
+ od = fi.path();
+ od = Option::fixPathToTargetOS(od);
+ if(QDir::isRelativePath(od))
+ od.prepend(Option::output_dir);
+ Option::output_dir = od;
+ return true;
+ }
+ return false;
+}
+
+QT_END_NAMESPACE
diff --git a/qmake/generators/makefile.h b/qmake/generators/makefile.h
new file mode 100644
index 0000000..a26a247
--- /dev/null
+++ b/qmake/generators/makefile.h
@@ -0,0 +1,267 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef MAKEFILE_H
+#define MAKEFILE_H
+
+#include "option.h"
+#include "project.h"
+#include "makefiledeps.h"
+#include <qtextstream.h>
+#include <qlist.h>
+#include <qhash.h>
+#include <qfileinfo.h>
+
+QT_BEGIN_NAMESPACE
+
+#ifdef Q_OS_WIN32
+#define QT_POPEN _popen
+#define QT_PCLOSE _pclose
+#else
+#define QT_POPEN popen
+#define QT_PCLOSE pclose
+#endif
+
+struct ReplaceExtraCompilerCacheKey
+{
+ mutable uint hash;
+ QString var, in, out, pwd;
+ ReplaceExtraCompilerCacheKey(const QString &v, const QStringList &i, const QStringList &o);
+ bool operator==(const ReplaceExtraCompilerCacheKey &f) const;
+ inline uint hashCode() const {
+ if(!hash)
+ hash = qHash(var) | qHash(in) | qHash(out) /*| qHash(pwd)*/;
+ return hash;
+ }
+};
+inline uint qHash(const ReplaceExtraCompilerCacheKey &f) { return f.hashCode(); }
+
+struct ReplaceExtraCompilerCacheKey;
+
+class MakefileGenerator : protected QMakeSourceFileInfo
+{
+ QString spec;
+ bool init_opath_already, init_already, no_io;
+ QHash<QString, bool> init_compiler_already;
+ QString build_args(const QString &outdir=QString());
+ void checkMultipleDefinition(const QString &, const QString &);
+
+ //internal caches
+ mutable QHash<QString, QMakeLocalFileName> depHeuristicsCache;
+ mutable QHash<QString, QStringList> dependsCache;
+ mutable QHash<ReplaceExtraCompilerCacheKey, QString> extraCompilerVariablesCache;
+
+protected:
+ QStringList createObjectList(const QStringList &sources);
+
+ //makefile style generator functions
+ void writeObj(QTextStream &, const QString &src);
+ void writeInstalls(QTextStream &t, const QString &installs, bool noBuild=false);
+ void writeHeader(QTextStream &t);
+ void writeSubDirs(QTextStream &t);
+ void writeMakeQmake(QTextStream &t);
+ void writeExtraVariables(QTextStream &t);
+ void writeExtraTargets(QTextStream &t);
+ void writeExtraCompilerTargets(QTextStream &t);
+ void writeExtraCompilerVariables(QTextStream &t);
+ virtual bool writeStubMakefile(QTextStream &t);
+ virtual bool writeMakefile(QTextStream &t);
+
+ //generating subtarget makefiles
+ struct SubTarget
+ {
+ QString name;
+ QString in_directory, out_directory;
+ QString profile, target, makefile;
+ QStringList depends;
+ };
+ enum SubTargetFlags {
+ SubTargetInstalls=0x01,
+ SubTargetOrdered=0x02,
+
+ SubTargetsNoFlags=0x00
+ };
+ void writeSubTargets(QTextStream &t, QList<SubTarget*> subtargets, int flags);
+
+ //extra compiler interface
+ bool verifyExtraCompiler(const QString &c, const QString &f);
+ virtual QString replaceExtraCompilerVariables(const QString &, const QStringList &, const QStringList &);
+ inline QString replaceExtraCompilerVariables(const QString &val, const QString &in, const QString &out)
+ { return replaceExtraCompilerVariables(val, QStringList(in), QStringList(out)); }
+
+ //interface to the source file info
+ QMakeLocalFileName fixPathForFile(const QMakeLocalFileName &, bool);
+ QMakeLocalFileName findFileForDep(const QMakeLocalFileName &, const QMakeLocalFileName &);
+ QFileInfo findFileInfo(const QMakeLocalFileName &);
+ QMakeProject *project;
+
+ //escape
+ virtual QString unescapeFilePath(const QString &path) const;
+ virtual QStringList unescapeFilePaths(const QStringList &path) const;
+ virtual QString escapeFilePath(const QString &path) const { return path; }
+ virtual QString escapeDependencyPath(const QString &path) const { return escapeFilePath(path); }
+ QStringList escapeFilePaths(const QStringList &paths) const;
+ QStringList escapeDependencyPaths(const QStringList &paths) const;
+
+ //initialization
+ void verifyCompilers();
+ virtual void init();
+ void initOutPaths();
+ struct Compiler
+ {
+ QString variable_in;
+ enum CompilerFlag {
+ CompilerNoFlags = 0x00,
+ CompilerBuiltin = 0x01,
+ CompilerNoCheckDeps = 0x02,
+ CompilerRemoveNoExist = 0x04
+ };
+ uint flags, type;
+ };
+ void initCompiler(const Compiler &comp);
+ enum VPATHFlag {
+ VPATH_NoFlag = 0x00,
+ VPATH_WarnMissingFiles = 0x01,
+ VPATH_RemoveMissingFiles = 0x02,
+ VPATH_NoFixify = 0x04
+ };
+ QStringList findFilesInVPATH(QStringList l, uchar flags, const QString &var="");
+
+ inline int findExecutable(const QStringList &cmdline)
+ { int ret; canExecute(cmdline, &ret); return ret; }
+ bool canExecute(const QStringList &cmdline, int *argv0) const;
+ inline bool canExecute(const QString &cmdline) const
+ { return canExecute(cmdline.split(' '), 0); }
+
+ bool mkdir(const QString &dir) const;
+ QString mkdir_p_asstring(const QString &dir, bool escape=true) const;
+
+ //subclasses can use these to query information about how the generator was "run"
+ QString buildArgs(const QString &outdir=QString());
+ QString specdir(const QString &outdir=QString());
+
+ virtual QStringList &findDependencies(const QString &file);
+ virtual bool doDepends() const { return Option::mkfile::do_deps; }
+
+ void filterIncludedFiles(const QString &);
+ virtual void processSources() {
+ filterIncludedFiles("SOURCES");
+ filterIncludedFiles("GENERATED_SOURCES");
+ }
+
+ //for cross-platform dependent directories
+ virtual void usePlatformDir();
+
+ //for installs
+ virtual QString defaultInstall(const QString &);
+
+ //for prl
+ QString prlFileName(bool fixify=true);
+ void writePrlFile();
+ bool processPrlFile(QString &);
+ virtual void processPrlVariable(const QString &, const QStringList &);
+ virtual void processPrlFiles();
+ virtual void writePrlFile(QTextStream &);
+
+ //make sure libraries are found
+ virtual bool findLibraries();
+
+ //for retrieving values and lists of values
+ virtual QString var(const QString &var);
+ QString varGlue(const QString &var, const QString &before, const QString &glue, const QString &after);
+ QString varList(const QString &var);
+ QString val(const QStringList &varList);
+ QString valGlue(const QStringList &varList, const QString &before, const QString &glue, const QString &after);
+ QString valList(const QStringList &varList);
+
+ QString filePrefixRoot(const QString &, const QString &);
+
+ //file fixification to unify all file names into a single pattern
+ enum FileFixifyType { FileFixifyAbsolute, FileFixifyRelative, FileFixifyDefault };
+ QString fileFixify(const QString& file, const QString &out_dir=QString(),
+ const QString &in_dir=QString(), FileFixifyType fix=FileFixifyDefault, bool canon=true) const;
+ inline QString fileFixify(const QString& file, FileFixifyType fix, bool canon=true) const
+ { return fileFixify(file, QString(), QString(), fix, canon); }
+ QStringList fileFixify(const QStringList& files, const QString &out_dir=QString(),
+ const QString &in_dir=QString(), FileFixifyType fix=FileFixifyDefault, bool canon=true) const;
+ inline QStringList fileFixify(const QStringList& files, FileFixifyType fix, bool canon=true) const
+ { return fileFixify(files, QString(), QString(), fix, canon); }
+
+public:
+ MakefileGenerator();
+ virtual ~MakefileGenerator();
+ QMakeProject *projectFile() const;
+ void setProjectFile(QMakeProject *p);
+
+ void setNoIO(bool o);
+ bool noIO() const;
+
+ inline bool exists(QString file) const { return fileInfo(file).exists(); }
+ QFileInfo fileInfo(QString file) const;
+
+ static MakefileGenerator *create(QMakeProject *);
+ virtual bool write();
+ virtual bool writeProjectMakefile();
+ virtual bool supportsMetaBuild() { return true; }
+ virtual bool supportsMergedBuilds() { return false; }
+ virtual bool mergeBuildProject(MakefileGenerator * /*other*/) { return false; }
+ virtual bool openOutput(QFile &, const QString &build) const;
+ virtual bool isWindowsShell() const { return Option::target_mode == Option::TARG_WIN_MODE; }
+};
+
+inline void MakefileGenerator::setNoIO(bool o)
+{ no_io = o; }
+
+inline bool MakefileGenerator::noIO() const
+{ return no_io; }
+
+inline QString MakefileGenerator::defaultInstall(const QString &)
+{ return QString(""); }
+
+inline bool MakefileGenerator::findLibraries()
+{ return true; }
+
+inline MakefileGenerator::~MakefileGenerator()
+{ }
+
+QT_END_NAMESPACE
+
+#endif // MAKEFILE_H
diff --git a/qmake/generators/makefiledeps.cpp b/qmake/generators/makefiledeps.cpp
new file mode 100644
index 0000000..852d6a2
--- /dev/null
+++ b/qmake/generators/makefiledeps.cpp
@@ -0,0 +1,963 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "makefiledeps.h"
+#include "option.h"
+#include <qdir.h>
+#include <qdatetime.h>
+#include <qfileinfo.h>
+#include <qbuffer.h>
+#include <qplatformdefs.h>
+#if defined(Q_OS_UNIX)
+# include <unistd.h>
+#else
+# include <io.h>
+#endif
+#include <qdebug.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+#include <share.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+#if 1
+#define qmake_endOfLine(c) (c == '\r' || c == '\n')
+#else
+inline bool qmake_endOfLine(const char &c) { return (c == '\r' || c == '\n'); }
+#endif
+
+//#define QMAKE_USE_CACHE
+
+QMakeLocalFileName::QMakeLocalFileName(const QString &name) : is_null(name.isNull())
+{
+ if(!name.isEmpty()) {
+ if(name.at(0) == QLatin1Char('"') && name.at(name.length()-2) == QLatin1Char('"'))
+ real_name = name.mid(1, name.length()-2);
+ else
+ real_name = name;
+ }
+}
+const QString
+&QMakeLocalFileName::local() const
+{
+ if(!is_null && local_name.isNull())
+ local_name = Option::fixPathToLocalOS(real_name, true);
+ return local_name;
+}
+
+struct SourceDependChildren;
+struct SourceFile {
+ SourceFile() : deps(0), type(QMakeSourceFileInfo::TYPE_UNKNOWN),
+ mocable(0), traversed(0), exists(1),
+ moc_checked(0), dep_checked(0), included_count(0) { }
+ ~SourceFile();
+ QMakeLocalFileName file;
+ SourceDependChildren *deps;
+ QMakeSourceFileInfo::SourceFileType type;
+ uint mocable : 1, traversed : 1, exists : 1;
+ uint moc_checked : 1, dep_checked : 1;
+ uchar included_count;
+};
+struct SourceDependChildren {
+ SourceFile **children;
+ int num_nodes, used_nodes;
+ SourceDependChildren() : children(0), num_nodes(0), used_nodes(0) { }
+ ~SourceDependChildren() { if(children) free(children); children = 0; }
+ void addChild(SourceFile *s) {
+ if(num_nodes <= used_nodes) {
+ num_nodes += 200;
+ children = (SourceFile**)realloc(children, sizeof(SourceFile*)*(num_nodes));
+ }
+ children[used_nodes++] = s;
+ }
+};
+SourceFile::~SourceFile() { delete deps; }
+class SourceFiles {
+ int hash(const char *);
+public:
+ SourceFiles();
+ ~SourceFiles();
+
+ SourceFile *lookupFile(const char *);
+ inline SourceFile *lookupFile(const QString &f) { return lookupFile(f.toLatin1().constData()); }
+ inline SourceFile *lookupFile(const QMakeLocalFileName &f) { return lookupFile(f.local().toLatin1().constData()); }
+ void addFile(SourceFile *, const char *k=0, bool own=true);
+
+ struct SourceFileNode {
+ SourceFileNode() : key(0), next(0), file(0), own_file(1) { }
+ ~SourceFileNode() {
+ delete [] key;
+ if(own_file)
+ delete file;
+ }
+ char *key;
+ SourceFileNode *next;
+ SourceFile *file;
+ uint own_file : 1;
+ } **nodes;
+ int num_nodes;
+};
+SourceFiles::SourceFiles()
+{
+ nodes = (SourceFileNode**)malloc(sizeof(SourceFileNode*)*(num_nodes=3037));
+ for(int n = 0; n < num_nodes; n++)
+ nodes[n] = 0;
+}
+
+SourceFiles::~SourceFiles()
+{
+ for(int n = 0; n < num_nodes; n++) {
+ for(SourceFileNode *next = nodes[n]; next;) {
+ SourceFileNode *next_next = next->next;
+ delete next;
+ next = next_next;
+ }
+ }
+ free(nodes);
+}
+
+int SourceFiles::hash(const char *file)
+{
+ uint h = 0, g;
+ while (*file) {
+ h = (h << 4) + *file;
+ if ((g = (h & 0xf0000000)) != 0)
+ h ^= g >> 23;
+ h &= ~g;
+ file++;
+ }
+ return h;
+}
+
+SourceFile *SourceFiles::lookupFile(const char *file)
+{
+ int h = hash(file) % num_nodes;
+ for(SourceFileNode *p = nodes[h]; p; p = p->next) {
+ if(!strcmp(p->key, file))
+ return p->file;
+ }
+ return 0;
+}
+
+void SourceFiles::addFile(SourceFile *p, const char *k, bool own_file)
+{
+ QByteArray ba = p->file.local().toLatin1();
+ if(!k)
+ k = ba;
+ int h = hash(k) % num_nodes;
+ SourceFileNode *pn = new SourceFileNode;
+ pn->own_file = own_file;
+ pn->key = qstrdup(k);
+ pn->file = p;
+ pn->next = nodes[h];
+ nodes[h] = pn;
+}
+
+void QMakeSourceFileInfo::dependTreeWalker(SourceFile *node, SourceDependChildren *place)
+{
+ if(node->traversed || !node->exists)
+ return;
+ place->addChild(node);
+ node->traversed = true; //set flag
+ if(node->deps) {
+ for(int i = 0; i < node->deps->used_nodes; i++)
+ dependTreeWalker(node->deps->children[i], place);
+ }
+}
+
+void QMakeSourceFileInfo::setDependencyPaths(const QList<QMakeLocalFileName> &l)
+{
+ // Ensure that depdirs does not contain the same paths several times, to minimize the stats
+ QList<QMakeLocalFileName> ll;
+ for (int i = 0; i < l.count(); ++i) {
+ if (!ll.contains(l.at(i)))
+ ll.append(l.at(i));
+ }
+ depdirs = ll;
+}
+
+QStringList QMakeSourceFileInfo::dependencies(const QString &file)
+{
+ QStringList ret;
+ if(!files)
+ return ret;
+
+ if(SourceFile *node = files->lookupFile(QMakeLocalFileName(file))) {
+ if(node->deps) {
+ /* I stick them into a SourceDependChildren here because it is faster to just
+ iterate over the list to stick them in the list, and reset the flag, then it is
+ to loop over the tree (about 50% faster I saw) --Sam */
+ SourceDependChildren place;
+ for(int i = 0; i < node->deps->used_nodes; i++)
+ dependTreeWalker(node->deps->children[i], &place);
+ if(place.children) {
+ for(int i = 0; i < place.used_nodes; i++) {
+ place.children[i]->traversed = false; //reset flag
+ ret.append(place.children[i]->file.real());
+ }
+ }
+ }
+ }
+ return ret;
+}
+
+int
+QMakeSourceFileInfo::included(const QString &file)
+{
+ if (!files)
+ return 0;
+
+ if(SourceFile *node = files->lookupFile(QMakeLocalFileName(file)))
+ return node->included_count;
+ return 0;
+}
+
+bool QMakeSourceFileInfo::mocable(const QString &file)
+{
+ if(SourceFile *node = files->lookupFile(QMakeLocalFileName(file)))
+ return node->mocable;
+ return false;
+}
+
+QMakeSourceFileInfo::QMakeSourceFileInfo(const QString &cf)
+{
+ //dep_mode
+ dep_mode = Recursive;
+
+ //quick project lookups
+ includes = files = 0;
+ files_changed = false;
+
+ //buffer
+ spare_buffer = 0;
+ spare_buffer_size = 0;
+
+ //cache
+ cachefile = cf;
+ if(!cachefile.isEmpty())
+ loadCache(cachefile);
+}
+
+QMakeSourceFileInfo::~QMakeSourceFileInfo()
+{
+ //cache
+ if(!cachefile.isEmpty() /*&& files_changed*/)
+ saveCache(cachefile);
+
+ //buffer
+ if(spare_buffer) {
+ free(spare_buffer);
+ spare_buffer = 0;
+ spare_buffer_size = 0;
+ }
+
+ //quick project lookup
+ delete files;
+ delete includes;
+}
+
+void QMakeSourceFileInfo::setCacheFile(const QString &cf)
+{
+ cachefile = cf;
+ loadCache(cachefile);
+}
+
+void QMakeSourceFileInfo::addSourceFiles(const QStringList &l, uchar seek,
+ QMakeSourceFileInfo::SourceFileType type)
+{
+ for(int i=0; i<l.size(); ++i)
+ addSourceFile(l.at(i), seek, type);
+}
+void QMakeSourceFileInfo::addSourceFile(const QString &f, uchar seek,
+ QMakeSourceFileInfo::SourceFileType type)
+{
+ if(!files)
+ files = new SourceFiles;
+
+ QMakeLocalFileName fn(f);
+ SourceFile *file = files->lookupFile(fn);
+ if(!file) {
+ file = new SourceFile;
+ file->file = fn;
+ files->addFile(file);
+ } else {
+ if(file->type != type && file->type != TYPE_UNKNOWN && type != TYPE_UNKNOWN)
+ warn_msg(WarnLogic, "%s is marked as %d, then %d!", f.toLatin1().constData(),
+ file->type, type);
+ }
+ if(type != TYPE_UNKNOWN)
+ file->type = type;
+
+ if(seek & SEEK_MOCS && !file->moc_checked)
+ findMocs(file);
+ if(seek & SEEK_DEPS && !file->dep_checked)
+ findDeps(file);
+}
+
+bool QMakeSourceFileInfo::containsSourceFile(const QString &f, SourceFileType type)
+{
+ if(SourceFile *file = files->lookupFile(QMakeLocalFileName(f)))
+ return (file->type == type || file->type == TYPE_UNKNOWN || type == TYPE_UNKNOWN);
+ return false;
+}
+
+char *QMakeSourceFileInfo::getBuffer(int s) {
+ if(!spare_buffer || spare_buffer_size < s)
+ spare_buffer = (char *)realloc(spare_buffer, spare_buffer_size=s);
+ return spare_buffer;
+}
+
+#ifndef S_ISDIR
+#define S_ISDIR(x) (x & _S_IFDIR)
+#endif
+
+QMakeLocalFileName QMakeSourceFileInfo::fixPathForFile(const QMakeLocalFileName &f, bool)
+{
+ return f;
+}
+
+QMakeLocalFileName QMakeSourceFileInfo::findFileForDep(const QMakeLocalFileName &/*dep*/,
+ const QMakeLocalFileName &/*file*/)
+{
+ return QMakeLocalFileName();
+}
+
+QFileInfo QMakeSourceFileInfo::findFileInfo(const QMakeLocalFileName &dep)
+{
+ return QFileInfo(dep.real());
+}
+
+bool QMakeSourceFileInfo::findDeps(SourceFile *file)
+{
+ if(file->dep_checked || file->type == TYPE_UNKNOWN)
+ return true;
+ files_changed = true;
+ file->dep_checked = true;
+
+ struct stat fst;
+ char *buffer = 0;
+ int buffer_len = 0;
+ {
+ int fd;
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+ if (_sopen_s(&fd, fixPathForFile(file->file, true).local().toLatin1().constData(),
+ _O_RDONLY, _SH_DENYNO, _S_IREAD) != 0)
+ fd = -1;
+#else
+ fd = open(fixPathForFile(file->file, true).local().toLatin1().constData(), O_RDONLY);
+#endif
+ if(fd == -1 || fstat(fd, &fst) || S_ISDIR(fst.st_mode))
+ return false;
+ buffer = getBuffer(fst.st_size);
+ for(int have_read = 0;
+ (have_read = QT_READ(fd, buffer + buffer_len, fst.st_size - buffer_len));
+ buffer_len += have_read);
+ QT_CLOSE(fd);
+ }
+ if(!buffer)
+ return false;
+ if(!file->deps)
+ file->deps = new SourceDependChildren;
+
+ int line_count = 1;
+
+ for(int x = 0; x < buffer_len; ++x) {
+ bool try_local = true;
+ char *inc = 0;
+ if(file->type == QMakeSourceFileInfo::TYPE_UI) {
+ // skip whitespaces
+ while(x < buffer_len && (*(buffer+x) == ' ' || *(buffer+x) == '\t'))
+ ++x;
+ if(*(buffer + x) == '<') {
+ ++x;
+ if(buffer_len >= x + 12 && !strncmp(buffer + x, "includehint", 11) &&
+ (*(buffer + x + 11) == ' ' || *(buffer + x + 11) == '>')) {
+ for(x += 11; *(buffer + x) != '>'; ++x);
+ int inc_len = 0;
+ for(x += 1 ; *(buffer + x + inc_len) != '<'; ++inc_len);
+ *(buffer + x + inc_len) = '\0';
+ inc = buffer + x;
+ } else if(buffer_len >= x + 13 && !strncmp(buffer + x, "customwidget", 12) &&
+ (*(buffer + x + 12) == ' ' || *(buffer + x + 12) == '>')) {
+ for(x += 13; *(buffer + x) != '>'; ++x); //skip up to >
+ while(x < buffer_len) {
+ for(x++; *(buffer + x) != '<'; ++x); //skip up to <
+ x++;
+ if(buffer_len >= x + 7 && !strncmp(buffer+x, "header", 6) &&
+ (*(buffer + x + 6) == ' ' || *(buffer + x + 6) == '>')) {
+ for(x += 7; *(buffer + x) != '>'; ++x); //skip up to >
+ int inc_len = 0;
+ for(x += 1 ; *(buffer + x + inc_len) != '<'; ++inc_len);
+ *(buffer + x + inc_len) = '\0';
+ inc = buffer + x;
+ break;
+ } else if(buffer_len >= x + 14 && !strncmp(buffer+x, "/customwidget", 13) &&
+ (*(buffer + x + 13) == ' ' || *(buffer + x + 13) == '>')) {
+ x += 14;
+ break;
+ }
+ }
+ } else if(buffer_len >= x + 8 && !strncmp(buffer + x, "include", 7) &&
+ (*(buffer + x + 7) == ' ' || *(buffer + x + 7) == '>')) {
+ for(x += 8; *(buffer + x) != '>'; ++x) {
+ if(buffer_len >= x + 9 && *(buffer + x) == 'i' &&
+ !strncmp(buffer + x, "impldecl", 8)) {
+ for(x += 8; *(buffer + x) != '='; ++x);
+ if(*(buffer + x) != '=')
+ continue;
+ for(++x; *(buffer+x) == '\t' || *(buffer+x) == ' '; ++x);
+ char quote = 0;
+ if(*(buffer+x) == '\'' || *(buffer+x) == '"') {
+ quote = *(buffer + x);
+ ++x;
+ }
+ int val_len;
+ for(val_len = 0; true; ++val_len) {
+ if(quote) {
+ if(*(buffer+x+val_len) == quote)
+ break;
+ } else if(*(buffer + x + val_len) == '>' ||
+ *(buffer + x + val_len) == ' ') {
+ break;
+ }
+ }
+//? char saved = *(buffer + x + val_len);
+ *(buffer + x + val_len) = '\0';
+ if(!strcmp(buffer+x, "in implementation")) {
+ //### do this
+ }
+ }
+ }
+ int inc_len = 0;
+ for(x += 1 ; *(buffer + x + inc_len) != '<'; ++inc_len);
+ *(buffer + x + inc_len) = '\0';
+ inc = buffer + x;
+ }
+ }
+ //read past new line now..
+ for(; x < buffer_len && !qmake_endOfLine(*(buffer + x)); ++x);
+ ++line_count;
+ } else if(file->type == QMakeSourceFileInfo::TYPE_QRC) {
+ } else if(file->type == QMakeSourceFileInfo::TYPE_C) {
+ for(int beginning=1; x < buffer_len; ++x) {
+ // whitespace comments and line-endings
+ for(; x < buffer_len; ++x) {
+ if(*(buffer+x) == ' ' || *(buffer+x) == '\t') {
+ // keep going
+ } else if(*(buffer+x) == '/') {
+ ++x;
+ if(buffer_len >= x) {
+ if(*(buffer+x) == '/') { //c++ style comment
+ for(; x < buffer_len && !qmake_endOfLine(*(buffer + x)); ++x);
+ beginning = 1;
+ } else if(*(buffer+x) == '*') { //c style comment
+ for(++x; x < buffer_len; ++x) {
+ if(*(buffer+x) == '*') {
+ if(x < buffer_len-1 && *(buffer + (x+1)) == '/') {
+ ++x;
+ break;
+ }
+ } else if(qmake_endOfLine(*(buffer+x))) {
+ ++line_count;
+ }
+ }
+ }
+ }
+ } else if(qmake_endOfLine(*(buffer+x))) {
+ ++line_count;
+ beginning = 1;
+ } else {
+ break;
+ }
+ }
+
+ if(x >= buffer_len)
+ break;
+
+ // preprocessor directive
+ if(beginning && *(buffer+x) == '#')
+ break;
+
+ // quoted strings
+ if(*(buffer+x) == '\'' || *(buffer+x) == '"') {
+ const char term = *(buffer+(x++));
+ for(; x < buffer_len; ++x) {
+ if(*(buffer+x) == term) {
+ ++x;
+ break;
+ } else if(*(buffer+x) == '\\') {
+ ++x;
+ } else if(qmake_endOfLine(*(buffer+x))) {
+ ++line_count;
+ }
+ }
+ }
+ beginning = 0;
+ }
+ if(x >= buffer_len)
+ break;
+
+ //got a preprocessor symbol
+ ++x;
+ while(x < buffer_len) {
+ if(*(buffer+x) != ' ' && *(buffer+x) != '\t')
+ break;
+ ++x;
+ }
+
+ int keyword_len = 0;
+ const char *keyword = buffer+x;
+ while(x+keyword_len < buffer_len) {
+ if(((*(buffer+x+keyword_len) < 'a' || *(buffer+x+keyword_len) > 'z')) &&
+ *(buffer+x+keyword_len) != '_') {
+ for(x+=keyword_len; //skip spaces after keyword
+ x < buffer_len && (*(buffer+x) == ' ' || *(buffer+x) == '\t');
+ x++);
+ break;
+ } else if(qmake_endOfLine(*(buffer+x+keyword_len))) {
+ x += keyword_len-1;
+ keyword_len = 0;
+ break;
+ }
+ keyword_len++;
+ }
+
+ if(keyword_len == 7 && !strncmp(keyword, "include", keyword_len)) {
+ char term = *(buffer + x);
+ if(term == '<') {
+ try_local = false;
+ term = '>';
+ } else if(term != '"') { //wtf?
+ continue;
+ }
+ x++;
+
+ int inc_len;
+ for(inc_len = 0; *(buffer + x + inc_len) != term && !qmake_endOfLine(*(buffer + x + inc_len)); ++inc_len);
+ *(buffer + x + inc_len) = '\0';
+ inc = buffer + x;
+ x += inc_len;
+ } else if(keyword_len == 13 && !strncmp(keyword, "qmake_warning", keyword_len)) {
+ char term = 0;
+ if(*(buffer + x) == '"')
+ term = '"';
+ if(*(buffer + x) == '\'')
+ term = '\'';
+ if(term)
+ x++;
+
+ int msg_len;
+ for(msg_len = 0; (term && *(buffer + x + msg_len) != term) &&
+ !qmake_endOfLine(*(buffer + x + msg_len)); ++msg_len);
+ *(buffer + x + msg_len) = '\0';
+ debug_msg(0, "%s:%d %s -- %s", file->file.local().toLatin1().constData(), line_count, keyword, buffer+x);
+ x += msg_len;
+ } else if(*(buffer+x) == '\'' || *(buffer+x) == '"') {
+ const char term = *(buffer+(x++));
+ while(x < buffer_len) {
+ if(*(buffer+x) == term)
+ break;
+ if(*(buffer+x) == '\\') {
+ x+=2;
+ } else {
+ if(qmake_endOfLine(*(buffer+x)))
+ ++line_count;
+ ++x;
+ }
+ }
+ } else {
+ --x;
+ }
+ }
+
+ if(inc) {
+ if(!includes)
+ includes = new SourceFiles;
+ SourceFile *dep = includes->lookupFile(inc);
+ if(!dep) {
+ bool exists = false;
+ QMakeLocalFileName lfn(inc);
+ if(QDir::isRelativePath(lfn.real())) {
+ if(try_local) {
+ QString dir = findFileInfo(file->file).path();
+ if(QDir::isRelativePath(dir))
+ dir.prepend(qmake_getpwd() + "/");
+ if(!dir.endsWith("/"))
+ dir += "/";
+ QMakeLocalFileName f(dir + lfn.local());
+ if(findFileInfo(f).exists()) {
+ lfn = fixPathForFile(f);
+ exists = true;
+ }
+ }
+ if(!exists) { //path lookup
+ for(QList<QMakeLocalFileName>::Iterator it = depdirs.begin(); it != depdirs.end(); ++it) {
+ QMakeLocalFileName f((*it).real() + Option::dir_sep + lfn.real());
+ QFileInfo fi(findFileInfo(f));
+ if(fi.exists() && !fi.isDir()) {
+ lfn = fixPathForFile(f);
+ exists = true;
+ break;
+ }
+ }
+ }
+ if(!exists) { //heuristic lookup
+ lfn = findFileForDep(QMakeLocalFileName(inc), file->file);
+ if((exists = !lfn.isNull()))
+ lfn = fixPathForFile(lfn);
+ }
+ } else {
+ exists = QFile::exists(lfn.real());
+ }
+ if(!lfn.isNull()) {
+ dep = files->lookupFile(lfn);
+ if(!dep) {
+ dep = new SourceFile;
+ dep->file = lfn;
+ dep->type = QMakeSourceFileInfo::TYPE_C;
+ files->addFile(dep);
+ includes->addFile(dep, inc, false);
+ }
+ dep->exists = exists;
+ }
+ }
+ if(dep && dep->file != file->file) {
+ dep->included_count++;
+ if(dep->exists) {
+ debug_msg(5, "%s:%d Found dependency to %s", file->file.real().toLatin1().constData(),
+ line_count, dep->file.local().toLatin1().constData());
+ file->deps->addChild(dep);
+ }
+ }
+ }
+ }
+ if(dependencyMode() == Recursive) { //done last because buffer is shared
+ for(int i = 0; i < file->deps->used_nodes; i++) {
+ if(!file->deps->children[i]->deps)
+ findDeps(file->deps->children[i]);
+ }
+ }
+ return true;
+}
+
+bool QMakeSourceFileInfo::findMocs(SourceFile *file)
+{
+ if(file->moc_checked)
+ return true;
+ files_changed = true;
+ file->moc_checked = true;
+
+ int buffer_len;
+ char *buffer = 0;
+ {
+ struct stat fst;
+ int fd;
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+ if (_sopen_s(&fd, fixPathForFile(file->file, true).local().toLocal8Bit().constData(),
+ _O_RDONLY, _SH_DENYRW, _S_IREAD) != 0)
+ fd = -1;
+#else
+ fd = open(fixPathForFile(file->file, true).local().toLocal8Bit().constData(), O_RDONLY);
+#endif
+ if(fd == -1 || fstat(fd, &fst) || S_ISDIR(fst.st_mode))
+ return false; //shouldn't happen
+ buffer = getBuffer(fst.st_size);
+ for(int have_read = buffer_len = 0;
+ (have_read = QT_READ(fd, buffer + buffer_len, fst.st_size - buffer_len));
+ buffer_len += have_read);
+ QT_CLOSE(fd);
+ }
+
+ debug_msg(2, "findMocs: %s", file->file.local().toLatin1().constData());
+ int line_count = 1;
+ bool ignore_qobject = false, ignore_qgadget = false;
+ /* qmake ignore Q_GADGET */
+ /* qmake ignore Q_OBJECT */
+ for(int x = 0; x < buffer_len; x++) {
+ if(*(buffer + x) == '/') {
+ ++x;
+ if(buffer_len >= x) {
+ if(*(buffer + x) == '/') { //c++ style comment
+ for(;x < buffer_len && !qmake_endOfLine(*(buffer + x)); ++x);
+ } else if(*(buffer + x) == '*') { //c style comment
+ for(++x; x < buffer_len; ++x) {
+ if(*(buffer + x) == 't' || *(buffer + x) == 'q') { //ignore
+ if(buffer_len >= (x + 20) &&
+ !strncmp(buffer + x + 1, "make ignore Q_OBJECT", 20)) {
+ debug_msg(2, "Mocgen: %s:%d Found \"qmake ignore Q_OBJECT\"",
+ file->file.real().toLatin1().constData(), line_count);
+ x += 20;
+ ignore_qobject = true;
+ } else if(buffer_len >= (x + 20) &&
+ !strncmp(buffer + x + 1, "make ignore Q_GADGET", 20)) {
+ debug_msg(2, "Mocgen: %s:%d Found \"qmake ignore Q_GADGET\"",
+ file->file.real().toLatin1().constData(), line_count);
+ x += 20;
+ ignore_qgadget = true;
+ }
+ } else if(*(buffer + x) == '*') {
+ if(buffer_len >= (x+1) && *(buffer + (x+1)) == '/') {
+ ++x;
+ break;
+ }
+ } else if(Option::debug_level && qmake_endOfLine(*(buffer + x))) {
+ ++line_count;
+ }
+ }
+ }
+ }
+ } else if(*(buffer+x) == '\'' || *(buffer+x) == '"') {
+ const char term = *(buffer+(x++));
+ while(x < buffer_len) {
+ if(*(buffer+x) == term)
+ break;
+ if(*(buffer+x) == '\\') {
+ x+=2;
+ } else {
+ if(qmake_endOfLine(*(buffer+x)))
+ ++line_count;
+ ++x;
+ }
+ }
+ }
+ if(Option::debug_level && qmake_endOfLine(*(buffer+x)))
+ ++line_count;
+ if(((buffer_len > x+2 && *(buffer+x+1) == 'Q' && *(buffer+x+2) == '_')
+ ||
+ (buffer_len > x+4 && *(buffer+x+1) == 'Q' && *(buffer+x+2) == 'O'
+ && *(buffer+x+3) == 'M' && *(buffer+x+4) == '_'))
+ &&
+ *(buffer + x) != '_' &&
+ (*(buffer + x) < 'a' || *(buffer + x) > 'z') &&
+ (*(buffer + x) < 'A' || *(buffer + x) > 'Z') &&
+ (*(buffer + x) < '0' || *(buffer + x) > '9')) {
+ ++x;
+ int match = 0;
+ static const char *interesting[] = { "OBJECT", "GADGET",
+ "M_OBJECT" };
+ for(int interest = 0, m1, m2; interest < 3; ++interest) {
+ if(interest == 0 && ignore_qobject)
+ continue;
+ else if(interest == 1 && ignore_qgadget)
+ continue;
+ for(m1 = 0, m2 = 0; *(interesting[interest]+m1); ++m1) {
+ if(*(interesting[interest]+m1) != *(buffer+x+2+m1)) {
+ m2 = -1;
+ break;
+ }
+ ++m2;
+ }
+ if(m1 == m2) {
+ match = m2 + 2;
+ break;
+ }
+ }
+ if(match && *(buffer+x+match) != '_' &&
+ (*(buffer+x+match) < 'a' || *(buffer+x+match) > 'z') &&
+ (*(buffer+x+match) < 'A' || *(buffer+x+match) > 'Z') &&
+ (*(buffer+x+match) < '0' || *(buffer+x+match) > '9')) {
+ if(Option::debug_level) {
+ *(buffer+x+match) = '\0';
+ debug_msg(2, "Mocgen: %s:%d Found MOC symbol %s", file->file.real().toLatin1().constData(),
+ line_count, buffer+x);
+ }
+ file->mocable = true;
+ return true;
+ }
+ }
+ }
+ return true;
+}
+
+
+void QMakeSourceFileInfo::saveCache(const QString &cf)
+{
+#ifdef QMAKE_USE_CACHE
+ if(cf.isEmpty())
+ return;
+
+ QFile file(QMakeLocalFileName(cf).local());
+ if(file.open(QIODevice::WriteOnly)) {
+ QTextStream stream(&file);
+ stream << qmake_version() << endl << endl; //version
+ { //cache verification
+ QMap<QString, QStringList> verify = getCacheVerification();
+ stream << verify.count() << endl;
+ for(QMap<QString, QStringList>::iterator it = verify.begin();
+ it != verify.end(); ++it) {
+ stream << it.key() << endl << it.value().join(";") << endl;
+ }
+ stream << endl;
+ }
+ if(files->nodes) {
+ for(int file = 0; file < files->num_nodes; ++file) {
+ for(SourceFiles::SourceFileNode *node = files->nodes[file]; node; node = node->next) {
+ stream << node->file->file.local() << endl; //source
+ stream << node->file->type << endl; //type
+
+ //depends
+ stream << ";";
+ if(node->file->deps) {
+ for(int depend = 0; depend < node->file->deps->used_nodes; ++depend) {
+ if(depend)
+ stream << ";";
+ stream << node->file->deps->children[depend]->file.local();
+ }
+ }
+ stream << endl;
+
+ stream << node->file->mocable << endl; //mocable
+ stream << endl; //just for human readability
+ }
+ }
+ }
+ stream.flush();
+ file.close();
+ }
+#else
+ Q_UNUSED(cf);
+#endif
+}
+
+void QMakeSourceFileInfo::loadCache(const QString &cf)
+{
+ if(cf.isEmpty())
+ return;
+
+#ifdef QMAKE_USE_CACHE
+ QMakeLocalFileName cache_file(cf);
+ int fd = open(QMakeLocalFileName(cf).local().toLatin1(), O_RDONLY);
+ if(fd == -1)
+ return;
+ QFileInfo cache_fi = findFileInfo(cache_file);
+ if(!cache_fi.exists() || cache_fi.isDir())
+ return;
+
+ QFile file;
+ if(!file.open(QIODevice::ReadOnly, fd))
+ return;
+ QTextStream stream(&file);
+
+ if(stream.readLine() == qmake_version()) { //version check
+ stream.skipWhiteSpace();
+
+ bool verified = true;
+ { //cache verification
+ QMap<QString, QStringList> verify;
+ int len = stream.readLine().toInt();
+ for(int i = 0; i < len; ++i) {
+ QString var = stream.readLine();
+ QString val = stream.readLine();
+ verify.insert(var, val.split(';', QString::SkipEmptyParts));
+ }
+ verified = verifyCache(verify);
+ }
+ if(verified) {
+ stream.skipWhiteSpace();
+ if(!files)
+ files = new SourceFiles;
+ while(!stream.atEnd()) {
+ QString source = stream.readLine();
+ QString type = stream.readLine();
+ QString depends = stream.readLine();
+ QString mocable = stream.readLine();
+ stream.skipWhiteSpace();
+
+ QMakeLocalFileName fn(source);
+ QFileInfo fi = findFileInfo(fn);
+
+ SourceFile *file = files->lookupFile(fn);
+ if(!file) {
+ file = new SourceFile;
+ file->file = fn;
+ files->addFile(file);
+ file->type = (SourceFileType)type.toInt();
+ file->exists = fi.exists();
+ }
+ if(fi.exists() && fi.lastModified() < cache_fi.lastModified()) {
+ if(!file->dep_checked) { //get depends
+ if(!file->deps)
+ file->deps = new SourceDependChildren;
+ file->dep_checked = true;
+ QStringList depend_list = depends.split(";", QString::SkipEmptyParts);
+ for(int depend = 0; depend < depend_list.size(); ++depend) {
+ QMakeLocalFileName dep_fn(depend_list.at(depend));
+ QFileInfo dep_fi(findFileInfo(dep_fn));
+ SourceFile *dep = files->lookupFile(dep_fn);
+ if(!dep) {
+ dep = new SourceFile;
+ dep->file = dep_fn;
+ dep->exists = dep_fi.exists();
+ dep->type = QMakeSourceFileInfo::TYPE_UNKNOWN;
+ files->addFile(dep);
+ }
+ dep->included_count++;
+ file->deps->addChild(dep);
+ }
+ }
+ if(!file->moc_checked) { //get mocs
+ file->moc_checked = true;
+ file->mocable = mocable.toInt();
+ }
+ }
+ }
+ }
+ }
+#endif
+}
+
+QMap<QString, QStringList> QMakeSourceFileInfo::getCacheVerification()
+{
+ return QMap<QString, QStringList>();
+}
+
+bool QMakeSourceFileInfo::verifyCache(const QMap<QString, QStringList> &v)
+{
+ return v == getCacheVerification();
+}
+
+QT_END_NAMESPACE
diff --git a/qmake/generators/makefiledeps.h b/qmake/generators/makefiledeps.h
new file mode 100644
index 0000000..182d401
--- /dev/null
+++ b/qmake/generators/makefiledeps.h
@@ -0,0 +1,132 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef MAKEFILEDEPS_H
+#define MAKEFILEDEPS_H
+
+#include <qstringlist.h>
+#include <qfileinfo.h>
+
+QT_BEGIN_NAMESPACE
+
+struct SourceFile;
+struct SourceDependChildren;
+class SourceFiles;
+
+class QMakeLocalFileName {
+ uint is_null : 1;
+ mutable QString real_name, local_name;
+public:
+ QMakeLocalFileName() : is_null(1) { }
+ QMakeLocalFileName(const QString &);
+ bool isNull() const { return is_null; }
+ inline const QString &real() const { return real_name; }
+ const QString &local() const;
+
+ bool operator==(const QMakeLocalFileName &other) {
+ return (this->real_name == other.real_name);
+ }
+ bool operator!=(const QMakeLocalFileName &other) {
+ return !(*this == other);
+ }
+};
+
+class QMakeSourceFileInfo
+{
+private:
+ //quick project lookups
+ SourceFiles *files, *includes;
+ bool files_changed;
+ QList<QMakeLocalFileName> depdirs;
+
+ //sleezy buffer code
+ char *spare_buffer;
+ int spare_buffer_size;
+ char *getBuffer(int s);
+
+ //actual guts
+ bool findMocs(SourceFile *);
+ bool findDeps(SourceFile *);
+ void dependTreeWalker(SourceFile *, SourceDependChildren *);
+
+ //cache
+ QString cachefile;
+
+protected:
+ virtual QMakeLocalFileName fixPathForFile(const QMakeLocalFileName &, bool forOpen=false);
+ virtual QMakeLocalFileName findFileForDep(const QMakeLocalFileName &, const QMakeLocalFileName &);
+ virtual QFileInfo findFileInfo(const QMakeLocalFileName &);
+
+public:
+ QMakeSourceFileInfo(const QString &cachefile="");
+ virtual ~QMakeSourceFileInfo();
+
+ QList<QMakeLocalFileName> dependencyPaths() const { return depdirs; }
+ void setDependencyPaths(const QList<QMakeLocalFileName> &);
+
+ enum DependencyMode { Recursive, NonRecursive };
+ inline void setDependencyMode(DependencyMode mode) { dep_mode = mode; }
+ inline DependencyMode dependencyMode() const { return dep_mode; }
+
+ enum SourceFileType { TYPE_UNKNOWN, TYPE_C, TYPE_UI, TYPE_QRC };
+ enum SourceFileSeek { SEEK_DEPS=0x01, SEEK_MOCS=0x02 };
+ void addSourceFiles(const QStringList &, uchar seek, SourceFileType type=TYPE_C);
+ void addSourceFile(const QString &, uchar seek, SourceFileType type=TYPE_C);
+ bool containsSourceFile(const QString &, SourceFileType type=TYPE_C);
+
+ int included(const QString &file);
+ QStringList dependencies(const QString &file);
+
+ bool mocable(const QString &file);
+
+ virtual QMap<QString, QStringList> getCacheVerification();
+ virtual bool verifyCache(const QMap<QString, QStringList> &);
+ void setCacheFile(const QString &cachefile); //auto caching
+ void loadCache(const QString &cf);
+ void saveCache(const QString &cf);
+
+private:
+ DependencyMode dep_mode;
+};
+
+QT_END_NAMESPACE
+
+#endif // MAKEFILEDEPS_H
diff --git a/qmake/generators/metamakefile.cpp b/qmake/generators/metamakefile.cpp
new file mode 100644
index 0000000..f0683a7
--- /dev/null
+++ b/qmake/generators/metamakefile.cpp
@@ -0,0 +1,490 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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
+{
+ bool init_flag;
+private:
+ 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);
+ makefiles += build;
+ }
+ 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
+{
+ bool init_flag;
+private:
+ 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;
+
+ 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 += '/';
+ 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(oldpwd))
+ subdir = QFileInfo(subdir_path.mid(oldpwd.length()));
+ }
+
+ //handle sub project
+ QMakeProject *sub_proj = new QMakeProject(project->properties());
+ 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;
+ 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;
+ }
+ 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();
+ 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;
+}
+
+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) {
+ 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();
+}
+
+//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"
+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, "No generator specified in config file: %s\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 {
+ 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)
+{
+ 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);
+ ret->init();
+ return ret;
+}
+
+QT_END_NAMESPACE
diff --git a/qmake/generators/metamakefile.h b/qmake/generators/metamakefile.h
new file mode 100644
index 0000000..cba0c75
--- /dev/null
+++ b/qmake/generators/metamakefile.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef METAMAKEFILE_H
+#define METAMAKEFILE_H
+
+#include <qlist.h>
+#include <qstring.h>
+
+QT_BEGIN_NAMESPACE
+
+class QMakeProject;
+class MakefileGenerator;
+
+class MetaMakefileGenerator
+{
+protected:
+ MetaMakefileGenerator(QMakeProject *p, const QString &n, bool op=true) : project(p), own_project(op), name(n) { }
+ QMakeProject *project;
+ bool own_project;
+ QString name;
+
+public:
+
+ virtual ~MetaMakefileGenerator();
+
+ static MetaMakefileGenerator *createMetaGenerator(QMakeProject *proj, const QString &name, bool op=true);
+ static MakefileGenerator *createMakefileGenerator(QMakeProject *proj, bool noIO = false);
+
+ inline QMakeProject *projectFile() const { return project; }
+
+ virtual bool init() = 0;
+ virtual int type() const { return -1; }
+ virtual bool write(const QString &oldpwd) = 0;
+};
+
+QT_END_NAMESPACE
+
+#endif // METAMAKEFILE_H
diff --git a/qmake/generators/projectgenerator.cpp b/qmake/generators/projectgenerator.cpp
new file mode 100644
index 0000000..7215818
--- /dev/null
+++ b/qmake/generators/projectgenerator.cpp
@@ -0,0 +1,510 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "projectgenerator.h"
+#include "option.h"
+#include <qdatetime.h>
+#include <qdir.h>
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qregexp.h>
+
+QT_BEGIN_NAMESPACE
+
+QString project_builtin_regx() //calculate the builtin regular expression..
+{
+ QString ret;
+ QStringList builtin_exts;
+ builtin_exts << Option::c_ext << Option::ui_ext << Option::yacc_ext << Option::lex_ext << ".ts" << ".xlf" << ".qrc";
+ builtin_exts += Option::h_ext + Option::cpp_ext;
+ for(int i = 0; i < builtin_exts.size(); ++i) {
+ if(!ret.isEmpty())
+ ret += "; ";
+ ret += QString("*") + builtin_exts[i];
+ }
+ return ret;
+}
+
+ProjectGenerator::ProjectGenerator() : MakefileGenerator(), init_flag(false)
+{
+}
+
+void
+ProjectGenerator::init()
+{
+ if(init_flag)
+ return;
+ int file_count = 0;
+ init_flag = true;
+ verifyCompilers();
+
+ project->read(QMakeProject::ReadFeatures);
+ project->variables()["CONFIG"].clear();
+
+ QMap<QString, QStringList> &v = project->variables();
+ QString templ = Option::user_template.isEmpty() ? QString("app") : Option::user_template;
+ if(!Option::user_template_prefix.isEmpty())
+ templ.prepend(Option::user_template_prefix);
+ v["TEMPLATE_ASSIGN"] += templ;
+
+ //figure out target
+ if(Option::output.fileName() == "-")
+ v["TARGET_ASSIGN"] = QStringList("unknown");
+ else
+ v["TARGET_ASSIGN"] = QStringList(QFileInfo(Option::output).baseName());
+
+ //the scary stuff
+ if(project->first("TEMPLATE_ASSIGN") != "subdirs") {
+ QString builtin_regex = project_builtin_regx();
+ QStringList dirs = Option::projfile::project_dirs;
+ if(Option::projfile::do_pwd) {
+ if(!v["INCLUDEPATH"].contains("."))
+ v["INCLUDEPATH"] += ".";
+ dirs.prepend(qmake_getpwd());
+ }
+
+ for(int i = 0; i < dirs.count(); ++i) {
+ QString dir, regex, pd = dirs.at(i);
+ bool add_depend = false;
+ if(exists(pd)) {
+ QFileInfo fi(fileInfo(pd));
+ if(fi.isDir()) {
+ dir = pd;
+ add_depend = true;
+ if(dir.right(1) != Option::dir_sep)
+ dir += Option::dir_sep;
+ if(Option::recursive) {
+ QStringList files = QDir(dir).entryList(QDir::Files);
+ for(int i = 0; i < (int)files.count(); i++) {
+ if(files[i] != "." && files[i] != "..")
+ dirs.append(dir + files[i] + QDir::separator() + builtin_regex);
+ }
+ }
+ regex = builtin_regex;
+ } else {
+ QString file = pd;
+ int s = file.lastIndexOf(Option::dir_sep);
+ if(s != -1)
+ dir = file.left(s+1);
+ if(addFile(file)) {
+ add_depend = true;
+ file_count++;
+ }
+ }
+ } else { //regexp
+ regex = pd;
+ }
+ if(!regex.isEmpty()) {
+ int s = regex.lastIndexOf(Option::dir_sep);
+ if(s != -1) {
+ dir = regex.left(s+1);
+ regex = regex.right(regex.length() - (s+1));
+ }
+ if(Option::recursive) {
+ QStringList entries = QDir(dir).entryList(QDir::Dirs);
+ for(int i = 0; i < (int)entries.count(); i++) {
+ if(entries[i] != "." && entries[i] != "..") {
+ dirs.append(dir + entries[i] + QDir::separator() + regex);
+ }
+ }
+ }
+ QStringList files = QDir(dir).entryList(QDir::nameFiltersFromString(regex));
+ for(int i = 0; i < (int)files.count(); i++) {
+ QString file = dir + files[i];
+ if (addFile(file)) {
+ add_depend = true;
+ file_count++;
+ }
+ }
+ }
+ if(add_depend && !dir.isEmpty() && !v["DEPENDPATH"].contains(dir, Qt::CaseInsensitive)) {
+ QFileInfo fi(fileInfo(dir));
+ if(fi.absoluteFilePath() != qmake_getpwd())
+ v["DEPENDPATH"] += fileFixify(dir);
+ }
+ }
+ }
+ if(!file_count) { //shall we try a subdir?
+ QStringList knownDirs = Option::projfile::project_dirs;
+ if(Option::projfile::do_pwd)
+ knownDirs.prepend(".");
+ const QString out_file = fileFixify(Option::output.fileName());
+ for(int i = 0; i < knownDirs.count(); ++i) {
+ QString pd = knownDirs.at(i);
+ if(exists(pd)) {
+ QString newdir = pd;
+ QFileInfo fi(fileInfo(newdir));
+ if(fi.isDir()) {
+ newdir = fileFixify(newdir);
+ QStringList &subdirs = v["SUBDIRS"];
+ if(exists(fi.filePath() + QDir::separator() + fi.fileName() + Option::pro_ext) &&
+ !subdirs.contains(newdir, Qt::CaseInsensitive)) {
+ subdirs.append(newdir);
+ } else {
+ QStringList profiles = QDir(newdir).entryList(QStringList("*" + Option::pro_ext), QDir::Files);
+ for(int i = 0; i < (int)profiles.count(); i++) {
+ QString nd = newdir;
+ if(nd == ".")
+ nd = "";
+ else if(!nd.isEmpty() && !nd.endsWith(QString(QChar(QDir::separator()))))
+ nd += QDir::separator();
+ nd += profiles[i];
+ fileFixify(nd);
+ if(profiles[i] != "." && profiles[i] != ".." &&
+ !subdirs.contains(nd, Qt::CaseInsensitive) && !out_file.endsWith(nd))
+ subdirs.append(nd);
+ }
+ }
+ if(Option::recursive) {
+ QStringList dirs = QDir(newdir).entryList(QDir::Dirs);
+ for(int i = 0; i < (int)dirs.count(); i++) {
+ QString nd = fileFixify(newdir + QDir::separator() + dirs[i]);
+ if(dirs[i] != "." && dirs[i] != ".." && !knownDirs.contains(nd, Qt::CaseInsensitive))
+ knownDirs.append(nd);
+ }
+ }
+ }
+ } else { //regexp
+ QString regx = pd, dir;
+ int s = regx.lastIndexOf(Option::dir_sep);
+ if(s != -1) {
+ dir = regx.left(s+1);
+ regx = regx.right(regx.length() - (s+1));
+ }
+ QStringList files = QDir(dir).entryList(QDir::nameFiltersFromString(regx), QDir::Dirs);
+ QStringList &subdirs = v["SUBDIRS"];
+ for(int i = 0; i < (int)files.count(); i++) {
+ QString newdir(dir + files[i]);
+ QFileInfo fi(fileInfo(newdir));
+ if(fi.fileName() != "." && fi.fileName() != "..") {
+ newdir = fileFixify(newdir);
+ if(exists(fi.filePath() + QDir::separator() + fi.fileName() + Option::pro_ext) &&
+ !subdirs.contains(newdir)) {
+ subdirs.append(newdir);
+ } else {
+ QStringList profiles = QDir(newdir).entryList(QStringList("*" + Option::pro_ext), QDir::Files);
+ for(int i = 0; i < (int)profiles.count(); i++) {
+ QString nd = newdir + QDir::separator() + files[i];
+ fileFixify(nd);
+ if(files[i] != "." && files[i] != ".." && !subdirs.contains(nd, Qt::CaseInsensitive)) {
+ if(newdir + files[i] != Option::output_dir + Option::output.fileName())
+ subdirs.append(nd);
+ }
+ }
+ }
+ if(Option::recursive && !knownDirs.contains(newdir, Qt::CaseInsensitive))
+ knownDirs.append(newdir);
+ }
+ }
+ }
+ }
+ v["TEMPLATE_ASSIGN"] = QStringList("subdirs");
+ return;
+ }
+
+ //setup deplist
+ QList<QMakeLocalFileName> deplist;
+ {
+ const QStringList &d = v["DEPENDPATH"];
+ for(int i = 0; i < d.size(); ++i)
+ deplist.append(QMakeLocalFileName(d[i]));
+ }
+ setDependencyPaths(deplist);
+
+ QStringList &h = v["HEADERS"];
+ bool no_qt_files = true;
+ QString srcs[] = { "SOURCES", "YACCSOURCES", "LEXSOURCES", "FORMS", QString() };
+ for(int i = 0; !srcs[i].isNull(); i++) {
+ const QStringList &l = v[srcs[i]];
+ QMakeSourceFileInfo::SourceFileType type = QMakeSourceFileInfo::TYPE_C;
+ QMakeSourceFileInfo::addSourceFiles(l, QMakeSourceFileInfo::SEEK_DEPS, type);
+ for(int i = 0; i < l.size(); ++i) {
+ QStringList tmp = QMakeSourceFileInfo::dependencies(l[i]);
+ if(!tmp.isEmpty()) {
+ for(int dep_it = 0; dep_it < tmp.size(); ++dep_it) {
+ QString dep = tmp[dep_it];
+ dep = fixPathToQmake(dep);
+ QString file_dir = dep.section(Option::dir_sep, 0, -2),
+ file_no_path = dep.section(Option::dir_sep, -1);
+ if(!file_dir.isEmpty()) {
+ for(int inc_it = 0; inc_it < deplist.size(); ++inc_it) {
+ QMakeLocalFileName inc = deplist[inc_it];
+ if(inc.local() == file_dir && !v["INCLUDEPATH"].contains(inc.real(), Qt::CaseInsensitive))
+ v["INCLUDEPATH"] += inc.real();
+ }
+ }
+ if(no_qt_files && file_no_path.indexOf(QRegExp("^q[a-z_0-9].h$")) != -1)
+ no_qt_files = false;
+ QString h_ext;
+ for(int hit = 0; hit < Option::h_ext.size(); ++hit) {
+ if(dep.endsWith(Option::h_ext.at(hit))) {
+ h_ext = Option::h_ext.at(hit);
+ break;
+ }
+ }
+ if(!h_ext.isEmpty()) {
+ for(int cppit = 0; cppit < Option::cpp_ext.size(); ++cppit) {
+ QString src(dep.left(dep.length() - h_ext.length()) +
+ Option::cpp_ext.at(cppit));
+ if(exists(src)) {
+ QStringList &srcl = v["SOURCES"];
+ if(!srcl.contains(src, Qt::CaseInsensitive))
+ srcl.append(src);
+ }
+ }
+ } else if(dep.endsWith(Option::lex_ext) &&
+ file_no_path.startsWith(Option::lex_mod)) {
+ addConfig("lex_included");
+ }
+ if(!h.contains(dep, Qt::CaseInsensitive))
+ h += dep;
+ }
+ }
+ }
+ }
+
+ //strip out files that are actually output from internal compilers (ie temporary files)
+ const QStringList &quc = project->variables()["QMAKE_EXTRA_COMPILERS"];
+ for(QStringList::ConstIterator it = quc.begin(); it != quc.end(); ++it) {
+ QString tmp_out = project->variables()[(*it) + ".output"].first();
+ if(tmp_out.isEmpty())
+ continue;
+
+ QStringList var_out = project->variables()[(*it) + ".variable_out"];
+ bool defaults = var_out.isEmpty();
+ for(int i = 0; i < var_out.size(); ++i) {
+ QString v = var_out.at(i);
+ if(v.startsWith("GENERATED_")) {
+ defaults = true;
+ break;
+ }
+ }
+ if(defaults) {
+ var_out << "SOURCES";
+ var_out << "HEADERS";
+ var_out << "FORMS";
+ }
+ const QStringList &tmp = project->variables()[(*it) + ".input"];
+ for(QStringList::ConstIterator it2 = tmp.begin(); it2 != tmp.end(); ++it2) {
+ QStringList &inputs = project->variables()[(*it2)];
+ for(QStringList::Iterator input = inputs.begin(); input != inputs.end(); ++input) {
+ QString path = replaceExtraCompilerVariables(tmp_out, (*input), QString());
+ path = fixPathToQmake(path).section('/', -1);
+ for(int i = 0; i < var_out.size(); ++i) {
+ QString v = var_out.at(i);
+ QStringList &list = project->variables()[v];
+ for(int src = 0; src < list.size(); ) {
+ if(list[src] == path || list[src].endsWith("/" + path))
+ list.removeAt(src);
+ else
+ ++src;
+ }
+ }
+ }
+ }
+ }
+}
+
+bool
+ProjectGenerator::writeMakefile(QTextStream &t)
+{
+ t << "######################################################################" << endl;
+ t << "# Automatically generated by qmake (" << qmake_version() << ") " << QDateTime::currentDateTime().toString() << endl;
+ t << "######################################################################" << endl << endl;
+ if(!Option::user_configs.isEmpty())
+ t << "CONFIG += " << Option::user_configs.join(" ") << endl;
+ int i;
+ for(i = 0; i < Option::before_user_vars.size(); ++i)
+ t << Option::before_user_vars[i] << endl;
+ t << getWritableVar("TEMPLATE_ASSIGN", false);
+ if(project->first("TEMPLATE_ASSIGN") == "subdirs") {
+ t << endl << "# Directories" << "\n"
+ << getWritableVar("SUBDIRS");
+ } else {
+ t << getWritableVar("TARGET_ASSIGN")
+ << getWritableVar("CONFIG", false)
+ << getWritableVar("CONFIG_REMOVE", false)
+ << getWritableVar("DEPENDPATH")
+ << getWritableVar("INCLUDEPATH") << endl;
+
+ t << "# Input" << "\n";
+ t << getWritableVar("HEADERS")
+ << getWritableVar("FORMS")
+ << getWritableVar("LEXSOURCES")
+ << getWritableVar("YACCSOURCES")
+ << getWritableVar("SOURCES")
+ << getWritableVar("RESOURCES")
+ << getWritableVar("TRANSLATIONS");
+ }
+ for(i = 0; i < Option::after_user_vars.size(); ++i)
+ t << Option::after_user_vars[i] << endl;
+ return true;
+}
+
+bool
+ProjectGenerator::addConfig(const QString &cfg, bool add)
+{
+ QString where = "CONFIG";
+ if(!add)
+ where = "CONFIG_REMOVE";
+ if(!project->variables()[where].contains(cfg)) {
+ project->variables()[where] += cfg;
+ return true;
+ }
+ return false;
+}
+
+bool
+ProjectGenerator::addFile(QString file)
+{
+ file = fileFixify(file, qmake_getpwd());
+ QString dir;
+ int s = file.lastIndexOf(Option::dir_sep);
+ if(s != -1)
+ dir = file.left(s+1);
+ if(file.mid(dir.length(), Option::h_moc_mod.length()) == Option::h_moc_mod)
+ return false;
+
+ QString where;
+ for(int cppit = 0; cppit < Option::cpp_ext.size(); ++cppit) {
+ if(file.endsWith(Option::cpp_ext[cppit])) {
+ where = "SOURCES";
+ break;
+ }
+ }
+ if(where.isEmpty()) {
+ for(int hit = 0; hit < Option::h_ext.size(); ++hit)
+ if(file.endsWith(Option::h_ext.at(hit))) {
+ where = "HEADERS";
+ break;
+ }
+ }
+ if(where.isEmpty()) {
+ for(int cit = 0; cit < Option::c_ext.size(); ++cit) {
+ if(file.endsWith(Option::c_ext[cit])) {
+ where = "SOURCES";
+ break;
+ }
+ }
+ }
+ if(where.isEmpty()) {
+ if(file.endsWith(Option::ui_ext))
+ where = "FORMS";
+ else if(file.endsWith(Option::lex_ext))
+ where = "LEXSOURCES";
+ else if(file.endsWith(Option::yacc_ext))
+ where = "YACCSOURCES";
+ else if(file.endsWith(".ts") || file.endsWith(".xlf"))
+ where = "TRANSLATIONS";
+ else if(file.endsWith(".qrc"))
+ where = "RESOURCES";
+ }
+
+ QString newfile = fixPathToQmake(fileFixify(file));
+
+ QStringList &endList = project->variables()[where];
+ if(!endList.contains(newfile, Qt::CaseInsensitive)) {
+ endList += newfile;
+ return true;
+ }
+ return false;
+}
+
+QString
+ProjectGenerator::getWritableVar(const QString &v, bool)
+{
+ QStringList &vals = project->variables()[v];
+ if(vals.isEmpty())
+ return "";
+
+ // If values contain spaces, ensure that they are quoted
+ for(QStringList::iterator it = vals.begin(); it != vals.end(); ++it) {
+ if ((*it).contains(' ') && !(*it).startsWith(' '))
+ *it = '\"' + *it + '\"';
+ }
+
+ QString ret;
+ if(v.endsWith("_REMOVE"))
+ ret = v.left(v.length() - 7) + " -= ";
+ else if(v.endsWith("_ASSIGN"))
+ ret = v.left(v.length() - 7) + " = ";
+ else
+ ret = v + " += ";
+ QString join = vals.join(" ");
+ if(ret.length() + join.length() > 80) {
+ QString spaces;
+ for(int i = 0; i < ret.length(); i++)
+ spaces += " ";
+ join = vals.join(" \\\n" + spaces);
+ }
+ return ret + join + "\n";
+}
+
+bool
+ProjectGenerator::openOutput(QFile &file, const QString &build) const
+{
+ QString outdir;
+ if(!file.fileName().isEmpty()) {
+ QFileInfo fi(fileInfo(file.fileName()));
+ if(fi.isDir())
+ outdir = fi.path() + QDir::separator();
+ }
+ if(!outdir.isEmpty() || file.fileName().isEmpty()) {
+ QString dir = qmake_getpwd();
+ int s = dir.lastIndexOf('/');
+ if(s != -1)
+ dir = dir.right(dir.length() - (s + 1));
+ file.setFileName(outdir + dir + Option::pro_ext);
+ }
+ return MakefileGenerator::openOutput(file, build);
+}
+
+
+QString
+ProjectGenerator::fixPathToQmake(const QString &file)
+{
+ QString ret = file;
+ if(Option::dir_sep != QLatin1String("/"))
+ ret = ret.replace(Option::dir_sep, QLatin1String("/"));
+ return ret;
+}
+
+QT_END_NAMESPACE
diff --git a/qmake/generators/projectgenerator.h b/qmake/generators/projectgenerator.h
new file mode 100644
index 0000000..8402d32
--- /dev/null
+++ b/qmake/generators/projectgenerator.h
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PROJECTGENERATOR_H
+#define PROJECTGENERATOR_H
+
+#include "makefile.h"
+
+QT_BEGIN_NAMESPACE
+
+class ProjectGenerator : public MakefileGenerator
+{
+ bool init_flag;
+ bool addFile(QString);
+ bool addConfig(const QString &, bool add=true);
+ QString getWritableVar(const QString &, bool fixPath=true);
+ QString fixPathToQmake(const QString &file);
+protected:
+ virtual void init();
+ virtual bool writeMakefile(QTextStream &);
+public:
+ ProjectGenerator();
+ ~ProjectGenerator();
+ virtual bool supportsMetaBuild() { return false; }
+ virtual bool openOutput(QFile &, const QString &) const;
+};
+
+inline ProjectGenerator::~ProjectGenerator()
+{ }
+
+QT_END_NAMESPACE
+
+#endif // PROJECTGENERATOR_H
diff --git a/qmake/generators/unix/unixmake.cpp b/qmake/generators/unix/unixmake.cpp
new file mode 100644
index 0000000..1f02fb5
--- /dev/null
+++ b/qmake/generators/unix/unixmake.cpp
@@ -0,0 +1,865 @@
+/****************************************************************************
+ **
+ ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+ **
+ ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ **
+ ****************************************************************************/
+
+#include "unixmake.h"
+#include "option.h"
+#include <qregexp.h>
+#include <qfile.h>
+#include <qhash.h>
+#include <qdir.h>
+#include <time.h>
+#include <qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+void
+UnixMakefileGenerator::init()
+{
+ if(init_flag)
+ return;
+ init_flag = true;
+
+ if(project->isEmpty("QMAKE_EXTENSION_SHLIB")) {
+ if(project->isEmpty("QMAKE_CYGWIN_SHLIB")) {
+ project->values("QMAKE_EXTENSION_SHLIB").append("so");
+ } else {
+ project->values("QMAKE_EXTENSION_SHLIB").append("dll");
+ }
+ }
+
+ if(!project->isEmpty("QMAKE_FAILED_REQUIREMENTS")) /* no point */
+ return;
+
+ QStringList &configs = project->values("CONFIG");
+ if(project->isEmpty("ICON") && !project->isEmpty("RC_FILE"))
+ project->values("ICON") = project->values("RC_FILE");
+ if(project->isEmpty("QMAKE_EXTENSION_PLUGIN"))
+ project->values("QMAKE_EXTENSION_PLUGIN").append(project->first("QMAKE_EXTENSION_SHLIB"));
+ if(project->isEmpty("QMAKE_COPY_FILE"))
+ project->values("QMAKE_COPY_FILE").append("$(COPY)");
+ if(project->isEmpty("QMAKE_STREAM_EDITOR"))
+ project->values("QMAKE_STREAM_EDITOR").append("sed");
+ if(project->isEmpty("QMAKE_COPY_DIR"))
+ project->values("QMAKE_COPY_DIR").append("$(COPY) -R");
+ if(project->isEmpty("QMAKE_INSTALL_FILE"))
+ project->values("QMAKE_INSTALL_FILE").append("$(COPY_FILE)");
+ if(project->isEmpty("QMAKE_INSTALL_DIR"))
+ project->values("QMAKE_INSTALL_DIR").append("$(COPY_DIR)");
+ if(project->isEmpty("QMAKE_INSTALL_PROGRAM"))
+ project->values("QMAKE_INSTALL_PROGRAM").append("$(COPY_FILE)");
+ if(project->isEmpty("QMAKE_LIBTOOL"))
+ project->values("QMAKE_LIBTOOL").append("libtool --silent");
+ if(project->isEmpty("QMAKE_SYMBOLIC_LINK"))
+ project->values("QMAKE_SYMBOLIC_LINK").append("ln -sf");
+
+ /* this should probably not be here, but I'm using it to wrap the .t files */
+ if(project->first("TEMPLATE") == "app")
+ project->values("QMAKE_APP_FLAG").append("1");
+ else if(project->first("TEMPLATE") == "lib")
+ project->values("QMAKE_LIB_FLAG").append("1");
+ else if(project->first("TEMPLATE") == "subdirs") {
+ MakefileGenerator::init();
+ if(project->isEmpty("MAKEFILE"))
+ project->values("MAKEFILE").append("Makefile");
+ if(project->isEmpty("QMAKE_QMAKE"))
+ project->values("QMAKE_QMAKE").append("qmake");
+ if(project->values("QMAKE_INTERNAL_QMAKE_DEPS").indexOf("qmake_all") == -1)
+ project->values("QMAKE_INTERNAL_QMAKE_DEPS").append("qmake_all");
+ return; /* subdirs is done */
+ }
+
+ //If the TARGET looks like a path split it into DESTDIR and the resulting TARGET
+ if(!project->isEmpty("TARGET")) {
+ project->values("TARGET") = escapeFilePaths(project->values("TARGET"));
+ QString targ = unescapeFilePath(project->first("TARGET"));
+ int slsh = qMax(targ.lastIndexOf('/'), targ.lastIndexOf(Option::dir_sep));
+ if(slsh != -1) {
+ if(project->isEmpty("DESTDIR"))
+ project->values("DESTDIR").append("");
+ else if(project->first("DESTDIR").right(1) != Option::dir_sep)
+ project->values("DESTDIR") = QStringList(project->first("DESTDIR") + Option::dir_sep);
+ project->values("DESTDIR") = QStringList(project->first("DESTDIR") + targ.left(slsh+1));
+ project->values("TARGET") = QStringList(targ.mid(slsh+1));
+ }
+ }
+
+ project->values("QMAKE_ORIG_TARGET") = project->values("TARGET");
+ project->values("QMAKE_ORIG_DESTDIR") = project->values("DESTDIR");
+ project->values("QMAKE_LIBS") += escapeFilePaths(project->values("LIBS"));
+ if((!project->isEmpty("QMAKE_LIB_FLAG") && !project->isActiveConfig("staticlib")) ||
+ (project->isActiveConfig("qt") && project->isActiveConfig("plugin"))) {
+ if(configs.indexOf("dll") == -1) configs.append("dll");
+ } else if(!project->isEmpty("QMAKE_APP_FLAG") || project->isActiveConfig("dll")) {
+ configs.removeAll("staticlib");
+ }
+ if(!project->isEmpty("QMAKE_INCREMENTAL"))
+ project->values("QMAKE_LFLAGS") += project->values("QMAKE_LFLAGS_INCREMENTAL");
+ else if(!project->isEmpty("QMAKE_LFLAGS_PREBIND") &&
+ !project->values("QMAKE_LIB_FLAG").isEmpty() &&
+ project->isActiveConfig("dll"))
+ project->values("QMAKE_LFLAGS") += project->values("QMAKE_LFLAGS_PREBIND");
+ if(!project->isEmpty("QMAKE_INCDIR"))
+ project->values("INCLUDEPATH") += project->values("QMAKE_INCDIR");
+ if(!project->isEmpty("QMAKE_LIBDIR")) {
+ const QStringList &libdirs = project->values("QMAKE_LIBDIR");
+ for(int i = 0; i < libdirs.size(); ++i) {
+ if(!project->isEmpty("QMAKE_LFLAGS_RPATH") && project->isActiveConfig("rpath_libdirs"))
+ project->values("QMAKE_LFLAGS") += var("QMAKE_LFLAGS_RPATH") + libdirs[i];
+ if (project->isActiveConfig("rvct_linker")) {
+ project->values("QMAKE_LIBDIR_FLAGS") += "--userlibpath " + escapeFilePath(libdirs[i]);
+ } else {
+ project->values("QMAKE_LIBDIR_FLAGS") += "-L" + escapeFilePath(libdirs[i]);
+ }
+ }
+ }
+ if(project->isActiveConfig("macx") && !project->isEmpty("QMAKE_FRAMEWORKPATH")) {
+ const QStringList &fwdirs = project->values("QMAKE_FRAMEWORKPATH");
+ for(int i = 0; i < fwdirs.size(); ++i) {
+ project->values("QMAKE_FRAMEWORKPATH_FLAGS") += "-F" + escapeFilePath(fwdirs[i]);
+ }
+ }
+ if(!project->isEmpty("QMAKE_RPATHDIR")) {
+ const QStringList &rpathdirs = project->values("QMAKE_RPATHDIR");
+ for(int i = 0; i < rpathdirs.size(); ++i) {
+ if(!project->isEmpty("QMAKE_LFLAGS_RPATH"))
+ project->values("QMAKE_LFLAGS") += var("QMAKE_LFLAGS_RPATH") + escapeFilePath(QFileInfo(rpathdirs[i]).absoluteFilePath());
+ }
+ }
+
+ project->values("QMAKE_FILETAGS") << "SOURCES" << "GENERATED_SOURCES" << "TARGET" << "DESTDIR";
+ if(!project->isEmpty("QMAKE_EXTRA_COMPILERS")) {
+ const QStringList &quc = project->values("QMAKE_EXTRA_COMPILERS");
+ for(int i = 0; i < quc.size(); ++i)
+ project->values("QMAKE_FILETAGS") += project->values(quc[i]+".input");
+ }
+
+ if(project->isActiveConfig("GNUmake") && !project->isEmpty("QMAKE_CFLAGS_DEPS"))
+ include_deps = true; //do not generate deps
+ if(project->isActiveConfig("compile_libtool"))
+ Option::obj_ext = ".lo"; //override the .o
+
+ MakefileGenerator::init();
+
+ QString comps[] = { "C", "CXX", "OBJC", "OBJCXX", QString() };
+ for(int i = 0; !comps[i].isNull(); i++) {
+ QString compile_flag = var("QMAKE_COMPILE_FLAG");
+ if(compile_flag.isEmpty())
+ compile_flag = "-c";
+
+ if(doPrecompiledHeaders() && !project->isEmpty("PRECOMPILED_HEADER")) {
+ QString pchFlags = var("QMAKE_" + comps[i] + "FLAGS_USE_PRECOMPILE");
+
+ QString pchBaseName;
+ if(!project->isEmpty("PRECOMPILED_DIR")) {
+ pchBaseName = Option::fixPathToTargetOS(project->first("PRECOMPILED_DIR"));
+ if(!pchBaseName.endsWith(Option::dir_sep))
+ pchBaseName += Option::dir_sep;
+ }
+ pchBaseName += project->first("QMAKE_ORIG_TARGET");
+
+ // replace place holders
+ pchFlags = pchFlags.replace("${QMAKE_PCH_INPUT}",
+ fileFixify(project->first("PRECOMPILED_HEADER")));
+ pchFlags = pchFlags.replace("${QMAKE_PCH_OUTPUT_BASE}", pchBaseName);
+ if (project->isActiveConfig("icc_pch_style")) {
+ // icc style
+ pchFlags = pchFlags.replace("${QMAKE_PCH_OUTPUT}",
+ pchBaseName + project->first("QMAKE_PCH_OUTPUT_EXT"));
+ }
+
+ if (!pchFlags.isEmpty())
+ compile_flag += " " + pchFlags;
+ }
+
+ QString cflags;
+ if(comps[i] == "OBJC" || comps[i] == "OBJCXX")
+ cflags += " $(CFLAGS)";
+ else
+ cflags += " $(" + comps[i] + "FLAGS)";
+ compile_flag += cflags + " $(INCPATH)";
+
+ QString compiler = comps[i];
+ if (compiler == "C")
+ compiler = "CC";
+
+ QString runComp = "QMAKE_RUN_" + compiler;
+ if(project->isEmpty(runComp))
+ project->values(runComp).append("$(" + compiler + ") " + compile_flag + " -o $obj $src");
+ QString runCompImp = "QMAKE_RUN_" + compiler + "_IMP";
+ if(project->isEmpty(runCompImp))
+ project->values(runCompImp).append("$(" + compiler + ") " + compile_flag + " -o \"$@\" \"$<\"");
+ }
+
+ if(project->isActiveConfig("macx") && !project->isEmpty("TARGET") && !project->isActiveConfig("compile_libtool") &&
+ ((project->isActiveConfig("build_pass") || project->isEmpty("BUILDS")))) {
+ QString bundle;
+ if(project->isActiveConfig("bundle") && !project->isEmpty("QMAKE_BUNDLE_EXTENSION")) {
+ bundle = unescapeFilePath(project->first("TARGET"));
+ if(!project->isEmpty("QMAKE_BUNDLE_NAME"))
+ bundle = unescapeFilePath(project->first("QMAKE_BUNDLE_NAME"));
+ if(!bundle.endsWith(project->first("QMAKE_BUNDLE_EXTENSION")))
+ bundle += project->first("QMAKE_BUNDLE_EXTENSION");
+ } else if(project->first("TEMPLATE") == "app" && project->isActiveConfig("app_bundle")) {
+ bundle = unescapeFilePath(project->first("TARGET"));
+ if(!project->isEmpty("QMAKE_APPLICATION_BUNDLE_NAME"))
+ bundle = unescapeFilePath(project->first("QMAKE_APPLICATION_BUNDLE_NAME"));
+ if(!bundle.endsWith(".app"))
+ bundle += ".app";
+ if(project->isEmpty("QMAKE_BUNDLE_LOCATION"))
+ project->values("QMAKE_BUNDLE_LOCATION").append("Contents/MacOS");
+ project->values("QMAKE_PKGINFO").append(project->first("DESTDIR") + bundle + "/Contents/PkgInfo");
+ project->values("QMAKE_BUNDLE_RESOURCE_FILE").append(project->first("DESTDIR") + bundle + "/Contents/Resources/empty.lproj");
+ } else if(project->first("TEMPLATE") == "lib" && !project->isActiveConfig("staticlib") &&
+ ((!project->isActiveConfig("plugin") && project->isActiveConfig("lib_bundle")) ||
+ (project->isActiveConfig("plugin") && project->isActiveConfig("plugin_bundle")))) {
+ bundle = unescapeFilePath(project->first("TARGET"));
+ if(project->isActiveConfig("plugin")) {
+ if(!project->isEmpty("QMAKE_PLUGIN_BUNDLE_NAME"))
+ bundle = unescapeFilePath(project->first("QMAKE_PLUGIN_BUNDLE_NAME"));
+ if(!project->isEmpty("QMAKE_BUNDLE_EXTENSION") && !bundle.endsWith(project->first("QMAKE_BUNDLE_EXTENSION")))
+ bundle += project->first("QMAKE_BUNDLE_EXTENSION");
+ else if(!bundle.endsWith(".plugin"))
+ bundle += ".plugin";
+ if(!project->isEmpty("QMAKE_BUNDLE_LOCATION"))
+ project->values("QMAKE_BUNDLE_LOCATION").append("Contents/MacOS");
+ } else {
+ if(!project->isEmpty("QMAKE_FRAMEWORK_BUNDLE_NAME"))
+ bundle = unescapeFilePath(project->first("QMAKE_FRAMEWORK_BUNDLE_NAME"));
+ if(!project->isEmpty("QMAKE_BUNDLE_EXTENSION") && !bundle.endsWith(project->first("QMAKE_BUNDLE_EXTENSION")))
+ bundle += project->first("QMAKE_BUNDLE_EXTENSION");
+ else if(!bundle.endsWith(".framework"))
+ bundle += ".framework";
+ }
+ }
+ if(!bundle.isEmpty()) {
+ project->values("QMAKE_BUNDLE") = QStringList(bundle);
+ project->values("ALL_DEPS") += project->first("QMAKE_PKGINFO");
+ project->values("ALL_DEPS") += project->first("QMAKE_BUNDLE_RESOURCE_FILE");
+ } else {
+ project->values("QMAKE_BUNDLE").clear();
+ project->values("QMAKE_BUNDLE_LOCATION").clear();
+ }
+ } else { //no bundling here
+ project->values("QMAKE_BUNDLE").clear();
+ project->values("QMAKE_BUNDLE_LOCATION").clear();
+ }
+
+ if(!project->isEmpty("QMAKE_INTERNAL_INCLUDED_FILES"))
+ project->values("DISTFILES") += project->values("QMAKE_INTERNAL_INCLUDED_FILES");
+ project->values("DISTFILES") += project->projectFile();
+
+ init2();
+ project->values("QMAKE_INTERNAL_PRL_LIBS") << "QMAKE_LIBDIR_FLAGS" << "QMAKE_FRAMEWORKPATH_FLAGS" << "QMAKE_LIBS";
+ if(!project->isEmpty("QMAKE_MAX_FILES_PER_AR")) {
+ bool ok;
+ int max_files = project->first("QMAKE_MAX_FILES_PER_AR").toInt(&ok);
+ QStringList ar_sublibs, objs = project->values("OBJECTS");
+ if(ok && max_files > 5 && max_files < (int)objs.count()) {
+ QString lib;
+ for(int i = 0, obj_cnt = 0, lib_cnt = 0; i != objs.size(); ++i) {
+ if((++obj_cnt) >= max_files) {
+ if(lib_cnt) {
+ lib.sprintf("lib%s-tmp%d.a",
+ project->first("QMAKE_ORIG_TARGET").toLatin1().constData(), lib_cnt);
+ ar_sublibs << lib;
+ obj_cnt = 0;
+ }
+ lib_cnt++;
+ }
+ }
+ }
+ if(!ar_sublibs.isEmpty()) {
+ project->values("QMAKE_AR_SUBLIBS") = ar_sublibs;
+ project->values("QMAKE_INTERNAL_PRL_LIBS") << "QMAKE_AR_SUBLIBS";
+ }
+ }
+
+ if(project->isActiveConfig("compile_libtool")) {
+ const QString libtoolify[] = { "QMAKE_RUN_CC", "QMAKE_RUN_CC_IMP",
+ "QMAKE_RUN_CXX", "QMAKE_RUN_CXX_IMP",
+ "QMAKE_LINK_THREAD", "QMAKE_LINK", "QMAKE_AR_CMD", "QMAKE_LINK_SHLIB_CMD",
+ QString() };
+ for(int i = 0; !libtoolify[i].isNull(); i++) {
+ QStringList &l = project->values(libtoolify[i]);
+ if(!l.isEmpty()) {
+ QString libtool_flags, comp_flags;
+ if(libtoolify[i].startsWith("QMAKE_LINK") || libtoolify[i] == "QMAKE_AR_CMD") {
+ libtool_flags += " --mode=link";
+ if(project->isActiveConfig("staticlib")) {
+ libtool_flags += " -static";
+ } else {
+ if(!project->isEmpty("QMAKE_LIB_FLAG")) {
+ int maj = project->first("VER_MAJ").toInt();
+ int min = project->first("VER_MIN").toInt();
+ int pat = project->first("VER_PAT").toInt();
+ comp_flags += " -version-info " + QString::number(10*maj + min) +
+ ":" + QString::number(pat) + ":0";
+ if(libtoolify[i] != "QMAKE_AR_CMD") {
+ QString rpath = Option::output_dir;
+ if(!project->isEmpty("DESTDIR")) {
+ rpath = project->first("DESTDIR");
+ if(QDir::isRelativePath(rpath))
+ rpath.prepend(Option::output_dir + Option::dir_sep);
+ }
+ comp_flags += " -rpath " + Option::fixPathToTargetOS(rpath, false);
+ }
+ }
+ }
+ if(project->isActiveConfig("plugin"))
+ libtool_flags += " -module";
+ } else {
+ libtool_flags += " --mode=compile";
+ }
+ l.first().prepend("$(LIBTOOL)" + libtool_flags + " ");
+ if(!comp_flags.isEmpty())
+ l.first() += comp_flags;
+ }
+ }
+ }
+}
+
+void
+UnixMakefileGenerator::processPrlVariable(const QString &var, const QStringList &l)
+{
+ if(var == "QMAKE_PRL_LIBS") {
+ project->values("QMAKE_CURRENT_PRL_LIBS") += l;
+ } else
+ MakefileGenerator::processPrlVariable(var, l);
+}
+
+QStringList
+&UnixMakefileGenerator::findDependencies(const QString &file)
+{
+ QStringList &ret = MakefileGenerator::findDependencies(file);
+ // Note: The QMAKE_IMAGE_COLLECTION file have all images
+ // as dependency, so don't add precompiled header then
+ if(doPrecompiledHeaders() && !project->isEmpty("PRECOMPILED_HEADER")
+ && file != project->first("QMAKE_IMAGE_COLLECTION")) {
+ QString header_prefix;
+ if(!project->isEmpty("PRECOMPILED_DIR"))
+ header_prefix = project->first("PRECOMPILED_DIR");
+ header_prefix += project->first("QMAKE_ORIG_TARGET") + project->first("QMAKE_PCH_OUTPUT_EXT");
+ if (project->isActiveConfig("icc_pch_style")) {
+ // icc style
+ for(QStringList::Iterator it = Option::cpp_ext.begin(); it != Option::cpp_ext.end(); ++it) {
+ if(file.endsWith(*it)) {
+ ret += header_prefix;
+ break;
+ }
+ }
+ } else {
+ // gcc style
+ header_prefix += Option::dir_sep + project->first("QMAKE_PRECOMP_PREFIX");
+ for(QStringList::Iterator it = Option::c_ext.begin(); it != Option::c_ext.end(); ++it) {
+ if(file.endsWith(*it)) {
+ if(!project->isEmpty("QMAKE_CFLAGS_PRECOMPILE")) {
+ QString precomp_c_h = header_prefix + "c";
+ if(!ret.contains(precomp_c_h))
+ ret += precomp_c_h;
+ }
+ if(project->isActiveConfig("objective_c")) {
+ if(!project->isEmpty("QMAKE_OBJCFLAGS_PRECOMPILE")) {
+ QString precomp_objc_h = header_prefix + "objective-c";
+ if(!ret.contains(precomp_objc_h))
+ ret += precomp_objc_h;
+ }
+ if(!project->isEmpty("QMAKE_OBJCXXFLAGS_PRECOMPILE")) {
+ QString precomp_objcpp_h = header_prefix + "objective-c++";
+ if(!ret.contains(precomp_objcpp_h))
+ ret += precomp_objcpp_h;
+ }
+ }
+ break;
+ }
+ }
+ for(QStringList::Iterator it = Option::cpp_ext.begin(); it != Option::cpp_ext.end(); ++it) {
+ if(file.endsWith(*it)) {
+ if(!project->isEmpty("QMAKE_CXXFLAGS_PRECOMPILE")) {
+ QString precomp_cpp_h = header_prefix + "c++";
+ if(!ret.contains(precomp_cpp_h))
+ ret += precomp_cpp_h;
+ }
+ if(project->isActiveConfig("objective_c")) {
+ if(!project->isEmpty("QMAKE_OBJCXXFLAGS_PRECOMPILE")) {
+ QString precomp_objcpp_h = header_prefix + "objective-c++";
+ if(!ret.contains(precomp_objcpp_h))
+ ret += precomp_objcpp_h;
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+ return ret;
+}
+
+bool
+UnixMakefileGenerator::findLibraries()
+{
+ QList<QMakeLocalFileName> libdirs, frameworkdirs;
+ frameworkdirs.append(QMakeLocalFileName("/System/Library/Frameworks"));
+ frameworkdirs.append(QMakeLocalFileName("/Library/Frameworks"));
+ const QString lflags[] = { "QMAKE_LIBDIR_FLAGS", "QMAKE_FRAMEWORKPATH_FLAGS", "QMAKE_LFLAGS", "QMAKE_LIBS", QString() };
+ for(int i = 0; !lflags[i].isNull(); i++) {
+ QStringList &l = project->values(lflags[i]);
+ for(QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
+ bool do_suffix = true;
+ QString stub, dir, extn, opt = (*it).trimmed();
+ if(opt.startsWith("-")) {
+ if(opt.startsWith("-L")) {
+ QMakeLocalFileName f(opt.right(opt.length()-2));
+ if(!libdirs.contains(f))
+ libdirs.append(f);
+ } else if(opt.startsWith("-l")) {
+ if (project->isActiveConfig("rvct_linker")) {
+ (*it) = "lib" + opt.mid(2) + ".so";
+ } else {
+ stub = opt.mid(2);
+ }
+ } else if(Option::target_mode == Option::TARG_MACX_MODE && opt.startsWith("-F")) {
+ frameworkdirs.append(QMakeLocalFileName(opt.right(opt.length()-2)));
+ } else if(Option::target_mode == Option::TARG_MACX_MODE && opt.startsWith("-framework")) {
+ if(opt.length() > 11) {
+ opt = opt.mid(11);
+ } else {
+ ++it;
+ opt = (*it);
+ }
+ do_suffix = false;
+ extn = "";
+ dir = "/System/Library/Frameworks/" + opt + ".framework/";
+ stub = opt;
+ }
+ } else {
+ extn = dir = "";
+ stub = opt;
+ int slsh = opt.lastIndexOf(Option::dir_sep);
+ if(slsh != -1) {
+ dir = opt.left(slsh);
+ stub = opt.mid(slsh+1);
+ }
+ QRegExp stub_reg("^.*lib(" + stub + "[^./=]*)\\.(.*)$");
+ if(stub_reg.exactMatch(stub)) {
+ stub = stub_reg.cap(1);
+ extn = stub_reg.cap(2);
+ }
+ }
+ if(!stub.isEmpty()) {
+ if(do_suffix && !project->isEmpty("QMAKE_" + stub.toUpper() + "_SUFFIX"))
+ stub += project->first("QMAKE_" + stub.toUpper() + "_SUFFIX");
+ bool found = false;
+ QStringList extens;
+ if(!extn.isNull())
+ extens << extn;
+ else
+ extens << project->values("QMAKE_EXTENSION_SHLIB").first() << "a";
+ for(QStringList::Iterator extit = extens.begin(); extit != extens.end(); ++extit) {
+ if(dir.isNull()) {
+ QString lib_stub;
+ for(QList<QMakeLocalFileName>::Iterator dep_it = libdirs.begin(); dep_it != libdirs.end(); ++dep_it) {
+ if(exists((*dep_it).local() + Option::dir_sep + "lib" + stub +
+ "." + (*extit))) {
+ lib_stub = stub;
+ break;
+ }
+ }
+ if(!lib_stub.isNull()) {
+ (*it) = "-l" + lib_stub;
+ found = true;
+ break;
+ }
+ } else {
+ if(exists("lib" + stub + "." + (*extit))) {
+ (*it) = "lib" + stub + "." + (*extit);
+ found = true;
+ break;
+ }
+ }
+ }
+ if(!found && project->isActiveConfig("compile_libtool")) {
+ for(int dep_i = 0; dep_i < libdirs.size(); ++dep_i) {
+ if(exists(libdirs[dep_i].local() + Option::dir_sep + "lib" + stub + Option::libtool_ext)) {
+ (*it) = libdirs[dep_i].real() + Option::dir_sep + "lib" + stub + Option::libtool_ext;
+ found = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ return false;
+}
+
+QString linkLib(const QString &file, const QString &libName) {
+ QString ret;
+ QRegExp reg("^.*lib(" + QRegExp::escape(libName) + "[^./=]*).*$");
+ if(reg.exactMatch(file))
+ ret = "-l" + reg.cap(1);
+ return ret;
+}
+
+void
+UnixMakefileGenerator::processPrlFiles()
+{
+ QList<QMakeLocalFileName> libdirs, frameworkdirs;
+ frameworkdirs.append(QMakeLocalFileName("/System/Library/Frameworks"));
+ frameworkdirs.append(QMakeLocalFileName("/Library/Frameworks"));
+ const QString lflags[] = { "QMAKE_LIBDIR_FLAGS", "QMAKE_FRAMEWORKPATH_FLAGS", "QMAKE_LFLAGS", "QMAKE_LIBS", QString() };
+ for(int i = 0; !lflags[i].isNull(); i++) {
+ QStringList &l = project->values(lflags[i]);
+ for(int lit = 0; lit < l.size(); ++lit) {
+ QString opt = l.at(lit).trimmed();
+ if(opt.startsWith("-")) {
+ if(opt.startsWith("-L")) {
+ QMakeLocalFileName l(opt.right(opt.length()-2));
+ if(!libdirs.contains(l))
+ libdirs.append(l);
+ } else if(opt.startsWith("-l")) {
+ QString lib = opt.right(opt.length() - 2);
+ for(int dep_i = 0; dep_i < libdirs.size(); ++dep_i) {
+ const QMakeLocalFileName &lfn = libdirs[dep_i];
+ if(!project->isActiveConfig("compile_libtool")) { //give them the .libs..
+ QString la = lfn.local() + Option::dir_sep + "lib" + lib + Option::libtool_ext;
+ if(exists(la) && QFile::exists(lfn.local() + Option::dir_sep + ".libs")) {
+ QString dot_libs = lfn.real() + Option::dir_sep + ".libs";
+ l.append("-L" + dot_libs);
+ libdirs.append(QMakeLocalFileName(dot_libs));
+ }
+ }
+
+ QString prl = lfn.local() + Option::dir_sep + "lib" + lib;
+ if(!project->isEmpty("QMAKE_" + lib.toUpper() + "_SUFFIX"))
+ prl += project->first("QMAKE_" + lib.toUpper() + "_SUFFIX");
+ if(processPrlFile(prl)) {
+ if(prl.startsWith(lfn.local()))
+ prl.replace(0, lfn.local().length(), lfn.real());
+ opt = linkLib(prl, lib);
+ break;
+ }
+ }
+ } else if(Option::target_mode == Option::TARG_MACX_MODE && opt.startsWith("-F")) {
+ QMakeLocalFileName f(opt.right(opt.length()-2));
+ if(!frameworkdirs.contains(f))
+ frameworkdirs.append(f);
+ } else if(Option::target_mode == Option::TARG_MACX_MODE && opt.startsWith("-framework")) {
+ if(opt.length() > 11)
+ opt = opt.mid(11);
+ else
+ opt = l.at(++lit);
+ opt = opt.trimmed();
+ const QList<QMakeLocalFileName> dirs = frameworkdirs + libdirs;
+ for(int dep_i = 0; dep_i < dirs.size(); ++dep_i) {
+ QString prl = dirs[dep_i].local() + "/" + opt + ".framework/" + opt + Option::prl_ext;
+ if(processPrlFile(prl))
+ break;
+ }
+ }
+ } else if(!opt.isNull()) {
+ QString lib = opt;
+ processPrlFile(lib);
+#if 0
+ if(ret)
+ opt = linkLib(lib, "");
+#endif
+ if(!opt.isEmpty())
+ l.replaceInStrings(lib, opt);
+ }
+
+ QStringList &prl_libs = project->values("QMAKE_CURRENT_PRL_LIBS");
+ if(!prl_libs.isEmpty()) {
+ for(int prl = 0; prl < prl_libs.size(); ++prl)
+ l.insert(lit+prl+1, prl_libs.at(prl));
+ prl_libs.clear();
+ }
+ }
+
+ //merge them into a logical order
+ if(!project->isActiveConfig("no_smart_library_merge") && !project->isActiveConfig("no_lflags_merge")) {
+ QStringList lflags;
+ for(int lit = 0; lit < l.size(); ++lit) {
+ QString opt = l.at(lit).trimmed();
+ if(opt.startsWith("-")) {
+ if(opt.startsWith("-L") ||
+ (Option::target_mode == Option::TARG_MACX_MODE && opt.startsWith("-F"))) {
+ if(lit == 0 || l.lastIndexOf(opt, lit-1) == -1)
+ lflags.append(opt);
+ } else if(opt.startsWith("-l")) {
+ if(lit == l.size()-1 || l.indexOf(opt, lit+1) == -1)
+ lflags.append(opt);
+ } else if(Option::target_mode == Option::TARG_MACX_MODE && opt.startsWith("-framework")) {
+ if(opt.length() > 11)
+ opt = opt.mid(11);
+ else
+ opt = l.at(++lit);
+ bool found = false;
+ for(int x = lit+1; x < l.size(); ++x) {
+ QString xf = l.at(x);
+ if(xf.startsWith("-framework")) {
+ QString framework;
+ if(xf.length() > 11)
+ framework = xf.mid(11);
+ else
+ framework = l.at(++x);
+ if(framework == opt) {
+ found = true;
+ break;
+ }
+ }
+ }
+ if(!found) {
+ lflags.append("-framework");
+ lflags.append(opt);
+ }
+ } else {
+ lflags.append(opt);
+ }
+ } else if(!opt.isNull()) {
+ if(lit == 0 || l.lastIndexOf(opt, lit-1) == -1)
+ lflags.append(opt);
+ }
+ }
+ l = lflags;
+ }
+ }
+}
+
+QString
+UnixMakefileGenerator::defaultInstall(const QString &t)
+{
+ if(t != "target" || project->first("TEMPLATE") == "subdirs")
+ return QString();
+
+ bool bundle = false;
+ const QString root = "$(INSTALL_ROOT)";
+ QStringList &uninst = project->values(t + ".uninstall");
+ QString ret, destdir=project->first("DESTDIR");
+ QString targetdir = Option::fixPathToTargetOS(project->first("target.path"), false);
+ if(!destdir.isEmpty() && destdir.right(1) != Option::dir_sep)
+ destdir += Option::dir_sep;
+ targetdir = fileFixify(targetdir, FileFixifyAbsolute);
+ if(targetdir.right(1) != Option::dir_sep)
+ targetdir += Option::dir_sep;
+
+ QStringList links;
+ QString target="$(TARGET)";
+ QStringList &targets = project->values(t + ".targets");
+ if(!project->isEmpty("QMAKE_BUNDLE")) {
+ target = project->first("QMAKE_BUNDLE");
+ bundle = true;
+ } else if(project->first("TEMPLATE") == "app") {
+ target = "$(QMAKE_TARGET)";
+ } else if(project->first("TEMPLATE") == "lib") {
+ if(project->isEmpty("QMAKE_CYGWIN_SHLIB")) {
+ if(!project->isActiveConfig("staticlib") && !project->isActiveConfig("plugin")) {
+ if(project->isEmpty("QMAKE_HPUX_SHLIB")) {
+ links << "$(TARGET0)" << "$(TARGET1)" << "$(TARGET2)";
+ } else {
+ links << "$(TARGET0)";
+ }
+ }
+ }
+ }
+ for(int i = 0; i < targets.size(); ++i) {
+ QString src = targets.at(i),
+ dst = filePrefixRoot(root, targetdir + src.section('/', -1));
+ if(!ret.isEmpty())
+ ret += "\n\t";
+ ret += "-$(INSTALL_FILE) \"" + src + "\" \"" + dst + "\"";
+ if(!uninst.isEmpty())
+ uninst.append("\n\t");
+ uninst.append("-$(DEL_FILE) \"" + dst + "\"");
+ }
+
+ if(!bundle && project->isActiveConfig("compile_libtool")) {
+ QString src_targ = target;
+ if(src_targ == "$(TARGET)")
+ src_targ = "$(TARGETL)";
+ QString dst_dir = fileFixify(targetdir, FileFixifyAbsolute);
+ if(QDir::isRelativePath(dst_dir))
+ dst_dir = Option::fixPathToTargetOS(Option::output_dir + Option::dir_sep + dst_dir);
+ ret = "-$(LIBTOOL) --mode=install cp \"" + src_targ + "\" \"" + filePrefixRoot(root, dst_dir) + "\"";
+ uninst.append("-$(LIBTOOL) --mode=uninstall \"" + src_targ + "\"");
+ } else {
+ QString src_targ = target;
+ if(!destdir.isEmpty())
+ src_targ = Option::fixPathToTargetOS(destdir + target, false);
+ QString dst_targ = filePrefixRoot(root, fileFixify(targetdir + target, FileFixifyAbsolute));
+ if(bundle) {
+ if(!ret.isEmpty())
+ ret += "\n\t";
+ ret += "$(DEL_FILE) -r \"" + dst_targ + "\"\n\t";
+ }
+ if(!ret.isEmpty())
+ ret += "\n\t";
+
+ QString copy_cmd("-");
+ if (bundle)
+ copy_cmd += "$(INSTALL_DIR)";
+ else if (project->first("TEMPLATE") == "lib" && project->isActiveConfig("staticlib"))
+ copy_cmd += "$(INSTALL_FILE)";
+ else
+ copy_cmd += "$(INSTALL_PROGRAM)";
+ copy_cmd += " \"" + src_targ + "\" \"" + dst_targ + "\"";
+ if(project->first("TEMPLATE") == "lib" && !project->isActiveConfig("staticlib")
+ && project->values(t + ".CONFIG").indexOf("fix_rpath") != -1) {
+ if(!project->isEmpty("QMAKE_FIX_RPATH")) {
+ ret += copy_cmd;
+ ret += "\n\t-" + var("QMAKE_FIX_RPATH") + " \"" +
+ dst_targ + "\" \"" + dst_targ + "\"";
+ } else if(!project->isEmpty("QMAKE_LFLAGS_RPATH")) {
+ ret += "-$(LINK) $(LFLAGS) " + var("QMAKE_LFLAGS_RPATH") + targetdir + " -o \"" +
+ dst_targ + "\" $(OBJECTS) $(LIBS) $(OBJCOMP)";
+ } else {
+ ret += copy_cmd;
+ }
+ } else {
+ ret += copy_cmd;
+ }
+
+ if(project->first("TEMPLATE") == "lib" && project->isActiveConfig("staticlib")) {
+ if(!project->isEmpty("QMAKE_RANLIB"))
+ ret += QString("\n\t$(RANLIB) \"") + dst_targ + "\"";
+ } else if(!project->isActiveConfig("debug") && !project->isActiveConfig("nostrip") && !project->isEmpty("QMAKE_STRIP")) {
+ ret += "\n\t-" + var("QMAKE_STRIP");
+ if(project->first("TEMPLATE") == "lib" && !project->isEmpty("QMAKE_STRIPFLAGS_LIB"))
+ ret += " " + var("QMAKE_STRIPFLAGS_LIB");
+ else if(project->first("TEMPLATE") == "app" && !project->isEmpty("QMAKE_STRIPFLAGS_APP"))
+ ret += " " + var("QMAKE_STRIPFLAGS_APP");
+ if(bundle)
+ ret = " \"" + dst_targ + "/Contents/MacOS/$(QMAKE_TARGET)\"";
+ else
+ ret += " \"" + dst_targ + "\"";
+ }
+ if(!uninst.isEmpty())
+ uninst.append("\n\t");
+ if(bundle)
+ uninst.append("-$(DEL_FILE) -r \"" + dst_targ + "\"");
+ else
+ uninst.append("-$(DEL_FILE) \"" + dst_targ + "\"");
+ if(!links.isEmpty()) {
+ for(int i = 0; i < links.size(); ++i) {
+ if(Option::target_mode == Option::TARG_WIN_MODE ||
+ Option::target_mode == Option::TARG_MAC9_MODE) {
+ } else if(Option::target_mode == Option::TARG_UNIX_MODE ||
+ Option::target_mode == Option::TARG_MACX_MODE) {
+ QString link = Option::fixPathToTargetOS(destdir + links[i], false);
+ int lslash = link.lastIndexOf(Option::dir_sep);
+ if(lslash != -1)
+ link = link.right(link.length() - (lslash + 1));
+ QString dst_link = filePrefixRoot(root, fileFixify(targetdir + link, FileFixifyAbsolute));
+ ret += "\n\t-$(SYMLINK) \"$(TARGET)\" \"" + dst_link + "\"";
+ if(!uninst.isEmpty())
+ uninst.append("\n\t");
+ uninst.append("-$(DEL_FILE) \"" + dst_link + "\"");
+ }
+ }
+ }
+ }
+ if(project->first("TEMPLATE") == "lib") {
+ QStringList types;
+ types << "prl" << "libtool" << "pkgconfig";
+ for(int i = 0; i < types.size(); ++i) {
+ const QString type = types.at(i);
+ QString meta;
+ if(type == "prl" && project->isActiveConfig("create_prl") && !project->isActiveConfig("no_install_prl") &&
+ !project->isEmpty("QMAKE_INTERNAL_PRL_FILE"))
+ meta = prlFileName(false);
+ if(type == "libtool" && project->isActiveConfig("create_libtool") && !project->isActiveConfig("compile_libtool"))
+ meta = libtoolFileName(false);
+ if(type == "pkgconfig" && project->isActiveConfig("create_pc"))
+ meta = pkgConfigFileName(false);
+ if(!meta.isEmpty()) {
+ QString src_meta = meta;
+ if(!destdir.isEmpty())
+ src_meta = Option::fixPathToTargetOS(destdir + meta, false);
+ QString dst_meta = filePrefixRoot(root, fileFixify(targetdir + meta, FileFixifyAbsolute));
+ if(!uninst.isEmpty())
+ uninst.append("\n\t");
+ uninst.append("-$(DEL_FILE) \"" + dst_meta + "\"");
+ const QString replace_rule("QMAKE_" + type.toUpper() + "_INSTALL_REPLACE");
+ const QString dst_meta_dir = fileInfo(dst_meta).path();
+ if(!dst_meta_dir.isEmpty()) {
+ if(!ret.isEmpty())
+ ret += "\n\t";
+ ret += mkdir_p_asstring(dst_meta_dir, true);
+ }
+ QString install_meta = "$(INSTALL_FILE) \"" + src_meta + "\" \"" + dst_meta + "\"";
+ if(project->isEmpty(replace_rule) || project->isActiveConfig("no_sed_meta_install")) {
+ if(!ret.isEmpty())
+ ret += "\n\t";
+ ret += "-" + install_meta;
+ } else {
+ if(!ret.isEmpty())
+ ret += "\n\t";
+ ret += "-$(SED)";
+ QStringList replace_rules = project->values(replace_rule);
+ for(int r = 0; r < replace_rules.size(); ++r) {
+ const QString match = project->first(replace_rules.at(r) + ".match"),
+ replace = project->first(replace_rules.at(r) + ".replace");
+ if(!match.isEmpty() /*&& match != replace*/)
+ ret += " -e \"s," + match + "," + replace + ",g\"";
+ }
+ ret += " \"" + src_meta + "\" >\"" + dst_meta + "\"";
+ //ret += " || " + install_meta;
+ }
+ }
+ }
+ }
+ return ret;
+}
+
+QString
+UnixMakefileGenerator::escapeFilePath(const QString &path) const
+{
+ QString ret = path;
+ if(!ret.isEmpty()) {
+ ret = unescapeFilePath(ret).replace(QLatin1Char(' '), QLatin1String("\\ "));
+ debug_msg(2, "EscapeFilePath: %s -> %s", path.toLatin1().constData(), ret.toLatin1().constData());
+ }
+ return ret;
+}
+
+QT_END_NAMESPACE
diff --git a/qmake/generators/unix/unixmake.h b/qmake/generators/unix/unixmake.h
new file mode 100644
index 0000000..a1c6233
--- /dev/null
+++ b/qmake/generators/unix/unixmake.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef UNIXMAKE_H
+#define UNIXMAKE_H
+
+#include "makefile.h"
+
+QT_BEGIN_NAMESPACE
+
+class UnixMakefileGenerator : public MakefileGenerator
+{
+ bool init_flag, include_deps;
+ bool writeMakefile(QTextStream &);
+ QString libtoolFileName(bool fixify=true);
+ void writeLibtoolFile(); // for libtool
+ QString pkgConfigPrefix() const;
+ QString pkgConfigFileName(bool fixify=true);
+ QString pkgConfigFixPath(QString) const;
+ void writePkgConfigFile(); // for pkg-config
+ void writePrlFile(QTextStream &);
+
+public:
+ UnixMakefileGenerator();
+ ~UnixMakefileGenerator();
+
+protected:
+ virtual bool doPrecompiledHeaders() const { return project->isActiveConfig("precompile_header"); }
+ virtual bool doDepends() const { return !include_deps && !Option::mkfile::do_stub_makefile && MakefileGenerator::doDepends(); }
+ virtual QString defaultInstall(const QString &);
+ virtual void processPrlVariable(const QString &, const QStringList &);
+ virtual void processPrlFiles();
+
+ virtual bool findLibraries();
+ virtual QString escapeFilePath(const QString &path) const;
+ virtual QStringList &findDependencies(const QString &);
+ virtual void init();
+
+ void writeMakeParts(QTextStream &);
+
+private:
+ void init2();
+};
+
+inline UnixMakefileGenerator::~UnixMakefileGenerator()
+{ }
+
+QT_END_NAMESPACE
+
+#endif // UNIXMAKE_H
diff --git a/qmake/generators/unix/unixmake2.cpp b/qmake/generators/unix/unixmake2.cpp
new file mode 100644
index 0000000..585ab55
--- /dev/null
+++ b/qmake/generators/unix/unixmake2.cpp
@@ -0,0 +1,1477 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "unixmake.h"
+#include "option.h"
+#include "meta.h"
+#include <qregexp.h>
+#include <qbytearray.h>
+#include <qfile.h>
+#include <qdir.h>
+#include <qdatetime.h>
+#include <qdebug.h>
+#include <time.h>
+
+QT_BEGIN_NAMESPACE
+
+UnixMakefileGenerator::UnixMakefileGenerator() : MakefileGenerator(), init_flag(false), include_deps(false)
+{
+
+}
+
+void
+UnixMakefileGenerator::writePrlFile(QTextStream &t)
+{
+ MakefileGenerator::writePrlFile(t);
+ // libtool support
+
+ if(project->isActiveConfig("create_libtool") && project->first("TEMPLATE") == "lib") { //write .la
+ if(project->isActiveConfig("compile_libtool"))
+ warn_msg(WarnLogic, "create_libtool specified with compile_libtool can lead to conflicting .la\n"
+ "formats, create_libtool has been disabled\n");
+ else
+ writeLibtoolFile();
+ }
+ // pkg-config support
+ if(project->isActiveConfig("create_pc") && project->first("TEMPLATE") == "lib")
+ writePkgConfigFile();
+}
+
+bool
+UnixMakefileGenerator::writeMakefile(QTextStream &t)
+{
+
+ writeHeader(t);
+ if(!project->values("QMAKE_FAILED_REQUIREMENTS").isEmpty()) {
+ t << "QMAKE = " << (project->isEmpty("QMAKE_QMAKE") ? QString("qmake") : var("QMAKE_QMAKE")) << endl;
+ QStringList &qut = project->values("QMAKE_EXTRA_TARGETS");
+ for(QStringList::ConstIterator it = qut.begin(); it != qut.end(); ++it)
+ t << *it << " ";
+ t << "first all clean install distclean uninstall qmake_all:" << "\n\t"
+ << "@echo \"Some of the required modules ("
+ << var("QMAKE_FAILED_REQUIREMENTS") << ") are not available.\"" << "\n\t"
+ << "@echo \"Skipped.\"" << endl << endl;
+ writeMakeQmake(t);
+ if(project->isEmpty("QMAKE_NOFORCE"))
+ t << "FORCE:" << endl << endl;
+ return true;
+ }
+
+ if (project->values("TEMPLATE").first() == "app" ||
+ project->values("TEMPLATE").first() == "lib") {
+ if(Option::mkfile::do_stub_makefile && MakefileGenerator::writeStubMakefile(t))
+ return true;
+ writeMakeParts(t);
+ return MakefileGenerator::writeMakefile(t);
+ } else if(project->values("TEMPLATE").first() == "subdirs") {
+ MakefileGenerator::writeSubDirs(t);
+ return true;
+ }
+ return false;
+}
+
+void
+UnixMakefileGenerator::writeMakeParts(QTextStream &t)
+{
+ QString deps = fileFixify(Option::output.fileName()), target_deps, prl;
+ bool do_incremental = (project->isActiveConfig("incremental") &&
+ !project->values("QMAKE_INCREMENTAL").isEmpty() &&
+ (!project->values("QMAKE_APP_FLAG").isEmpty() ||
+ (!project->isActiveConfig("staticlib")))),
+ src_incremental=false;
+
+ t << "####### Compiler, tools and options" << endl << endl;
+ t << "CC = " << var("QMAKE_CC") << endl;
+ t << "CXX = " << var("QMAKE_CXX") << endl;
+ t << "DEFINES = "
+ << varGlue("PRL_EXPORT_DEFINES","-D"," -D"," ")
+ << varGlue("DEFINES","-D"," -D","") << endl;
+ t << "CFLAGS = " << var("QMAKE_CFLAGS") << " $(DEFINES)" << endl;
+ t << "CXXFLAGS = " << var("QMAKE_CXXFLAGS") << " $(DEFINES)" << endl;
+ t << "INCPATH = " << "-I" << specdir();
+ if(!project->isActiveConfig("no_include_pwd")) {
+ QString pwd = escapeFilePath(fileFixify(qmake_getpwd()));
+ if(pwd.isEmpty())
+ pwd = ".";
+ t << " -I" << pwd;
+ }
+ {
+ const QStringList &incs = project->values("INCLUDEPATH");
+ for(int i = 0; i < incs.size(); ++i) {
+ QString inc = escapeFilePath(incs.at(i));
+ if(!inc.isEmpty())
+ t << " " << "-I" << inc;
+ }
+ }
+ if(!project->isEmpty("QMAKE_FRAMEWORKPATH_FLAGS"))
+ t << " " << var("QMAKE_FRAMEWORKPATH_FLAGS");
+ t << endl;
+
+ if(!project->isActiveConfig("staticlib")) {
+ t << "LINK = " << var("QMAKE_LINK") << endl;
+ t << "LFLAGS = " << var("QMAKE_LFLAGS") << endl;
+ t << "LIBS = " << "$(SUBLIBS) " << var("QMAKE_FRAMEWORKDIR_FLAGS") << " "
+ << var("QMAKE_LIBDIR_FLAGS") << " " << var("QMAKE_LIBS") << endl;
+ }
+
+ t << "AR = " << var("QMAKE_AR") << endl;
+ t << "RANLIB = " << var("QMAKE_RANLIB") << endl;
+ t << "QMAKE = " << (project->isEmpty("QMAKE_QMAKE") ? QString("qmake") : var("QMAKE_QMAKE")) << endl;
+ t << "TAR = " << var("QMAKE_TAR") << endl;
+ t << "COMPRESS = " << var("QMAKE_GZIP") << endl;
+ if(project->isActiveConfig("compile_libtool"))
+ t << "LIBTOOL = " << var("QMAKE_LIBTOOL") << endl;
+ t << "COPY = " << var("QMAKE_COPY") << endl;
+ t << "SED = " << var("QMAKE_STREAM_EDITOR") << endl;
+ t << "COPY_FILE = " << var("QMAKE_COPY_FILE") << endl;
+ t << "COPY_DIR = " << var("QMAKE_COPY_DIR") << endl;
+ t << "INSTALL_FILE = " << var("QMAKE_INSTALL_FILE") << endl;
+ t << "INSTALL_DIR = " << var("QMAKE_INSTALL_DIR") << endl;
+ t << "INSTALL_PROGRAM = " << var("QMAKE_INSTALL_PROGRAM") << endl;
+
+ t << "DEL_FILE = " << var("QMAKE_DEL_FILE") << endl;
+ t << "SYMLINK = " << var("QMAKE_SYMBOLIC_LINK") << endl;
+ t << "DEL_DIR = " << var("QMAKE_DEL_DIR") << endl;
+ t << "MOVE = " << var("QMAKE_MOVE") << endl;
+ t << "CHK_DIR_EXISTS= " << var("QMAKE_CHK_DIR_EXISTS") << endl;
+ t << "MKDIR = " << var("QMAKE_MKDIR") << endl;
+ if(!project->isEmpty("QMAKE_MACOSX_DEPLOYMENT_TARGET"))
+ t << "export MACOSX_DEPLOYMENT_TARGET = " //exported to children processes
+ << project->first("QMAKE_MACOSX_DEPLOYMENT_TARGET") << endl;
+ t << endl;
+
+ t << "####### Output directory" << endl << endl;
+ if (! project->values("OBJECTS_DIR").isEmpty())
+ t << "OBJECTS_DIR = " << var("OBJECTS_DIR") << endl;
+ else
+ t << "OBJECTS_DIR = ./" << endl;
+ t << endl;
+
+ /* files */
+ t << "####### Files" << endl << endl;
+ t << "SOURCES = " << valList(escapeFilePaths(project->values("SOURCES"))) << " "
+ << valList(escapeFilePaths(project->values("GENERATED_SOURCES"))) << endl;
+ if(do_incremental) {
+ QStringList &objs = project->values("OBJECTS"), &incrs = project->values("QMAKE_INCREMENTAL"), incrs_out;
+ t << "OBJECTS = ";
+ for(QStringList::Iterator objit = objs.begin(); objit != objs.end(); ++objit) {
+ bool increment = false;
+ for(QStringList::Iterator incrit = incrs.begin(); incrit != incrs.end(); ++incrit) {
+ if((*objit).indexOf(QRegExp((*incrit), Qt::CaseSensitive,
+ QRegExp::Wildcard)) != -1) {
+ increment = true;
+ incrs_out.append((*objit));
+ break;
+ }
+ }
+ if(!increment)
+ t << "\\\n\t\t" << (*objit);
+ }
+ if(incrs_out.count() == objs.count()) { //we just switched places, no real incrementals to be done!
+ t << escapeFilePaths(incrs_out).join(" \\\n\t\t") << endl;
+ } else if(!incrs_out.count()) {
+ t << endl;
+ } else {
+ src_incremental = true;
+ t << endl;
+ t << "INCREMENTAL_OBJECTS = " << escapeFilePaths(incrs_out).join(" \\\n\t\t") << endl;
+ }
+ } else {
+ t << "OBJECTS = " << valList(escapeFilePaths(project->values("OBJECTS"))) << endl;
+ }
+ if(do_incremental && !src_incremental)
+ do_incremental = false;
+ t << "DIST = " << valList(fileFixify(project->values("DISTFILES"))) << endl;
+ t << "QMAKE_TARGET = " << var("QMAKE_ORIG_TARGET") << endl;
+ t << "DESTDIR = " << var("DESTDIR") << endl;
+ if(project->isActiveConfig("compile_libtool"))
+ t << "TARGETL = " << var("TARGET_la") << endl;
+ t << "TARGET = " << escapeFilePath(var("TARGET")) << endl;
+ if(project->isActiveConfig("plugin")) {
+ t << "TARGETD = " << escapeFilePath(var("TARGET")) << endl;
+ } else if(!project->isActiveConfig("staticlib") && project->values("QMAKE_APP_FLAG").isEmpty()) {
+ t << "TARGETA = " << escapeFilePath(var("TARGETA")) << endl;
+ if(!project->isEmpty("QMAKE_BUNDLE")) {
+ t << "TARGETD = " << escapeFilePath(var("TARGET_x.y")) << endl;
+ t << "TARGET0 = " << escapeFilePath(var("TARGET_")) << endl;
+ } else if(project->isEmpty("QMAKE_HPUX_SHLIB")) {
+ t << "TARGETD = " << escapeFilePath(var("TARGET_x.y.z")) << endl;
+ t << "TARGET0 = " << escapeFilePath(var("TARGET_")) << endl;
+ t << "TARGET1 = " << escapeFilePath(var("TARGET_x")) << endl;
+ t << "TARGET2 = " << escapeFilePath(var("TARGET_x.y")) << endl;
+ } else {
+ t << "TARGETD = " << escapeFilePath(var("TARGET_x")) << endl;
+ t << "TARGET0 = " << escapeFilePath(var("TARGET_")) << endl;
+ }
+ }
+ writeExtraCompilerVariables(t);
+ writeExtraVariables(t);
+ t << endl;
+
+ // blasted includes
+ QStringList &qeui = project->values("QMAKE_EXTRA_INCLUDES");
+ QStringList::Iterator it;
+ for(it = qeui.begin(); it != qeui.end(); ++it)
+ t << "include " << (*it) << endl;
+
+ /* rules */
+ t << "first: all" << endl;
+ t << "####### Implicit rules" << endl << endl;
+ t << ".SUFFIXES: " << Option::obj_ext;
+ for(QStringList::Iterator cit = Option::c_ext.begin(); cit != Option::c_ext.end(); ++cit)
+ t << " " << (*cit);
+ for(QStringList::Iterator cppit = Option::cpp_ext.begin(); cppit != Option::cpp_ext.end(); ++cppit)
+ t << " " << (*cppit);
+ t << endl << endl;
+ for(QStringList::Iterator cppit = Option::cpp_ext.begin(); cppit != Option::cpp_ext.end(); ++cppit)
+ t << (*cppit) << Option::obj_ext << ":\n\t" << var("QMAKE_RUN_CXX_IMP") << endl << endl;
+ for(QStringList::Iterator cit = Option::c_ext.begin(); cit != Option::c_ext.end(); ++cit)
+ t << (*cit) << Option::obj_ext << ":\n\t" << var("QMAKE_RUN_CC_IMP") << endl << endl;
+
+ if(include_deps) {
+ QString cmd=var("QMAKE_CFLAGS_DEPS") + " ";
+ cmd += varGlue("DEFINES","-D"," -D","") + varGlue("PRL_EXPORT_DEFINES"," -D"," -D","");
+ if(!project->isEmpty("QMAKE_ABSOLUTE_SOURCE_PATH"))
+ cmd += " -I" + project->first("QMAKE_ABSOLUTE_SOURCE_PATH") + " ";
+ cmd += " $(INCPATH) " + varGlue("DEPENDPATH", "-I", " -I", "");
+ QString odir;
+ if(!project->values("OBJECTS_DIR").isEmpty())
+ odir = project->first("OBJECTS_DIR");
+ t << "###### Dependencies" << endl << endl;
+ t << odir << ".deps/%.d: %.cpp\n\t";
+ if(project->isActiveConfig("echo_depend_creation"))
+ t << "@echo Creating depend for $<" << "\n\t";
+ t << mkdir_p_asstring("$(@D)") << "\n\t"
+ << "@$(CXX) " << cmd << " $< | sed \"s,^\\($(*F).o\\):," << odir << "\\1:,g\" >$@" << endl << endl;
+
+ t << odir << ".deps/%.d: %.c\n\t";
+ if(project->isActiveConfig("echo_depend_creation"))
+ t << "@echo Creating depend for $<" << "\n\t";
+ t << mkdir_p_asstring("$(@D)") << "\n\t"
+ << "@$(CC) " << cmd << " $< | sed \"s,^\\($(*F).o\\):," << odir << "\\1:,g\" >$@" << endl << endl;
+
+ QString src[] = { "SOURCES", "GENERATED_SOURCES", QString() };
+ for(int x = 0; !src[x].isNull(); x++) {
+ QStringList &l = project->values(src[x]);
+ for(QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
+ if(!(*it).isEmpty()) {
+ QString d_file;
+ for(QStringList::Iterator cit = Option::c_ext.begin();
+ cit != Option::c_ext.end(); ++cit) {
+ if((*it).endsWith((*cit))) {
+ d_file = (*it).left((*it).length() - (*cit).length());
+ break;
+ }
+ }
+ if(d_file.isEmpty()) {
+ for(QStringList::Iterator cppit = Option::cpp_ext.begin();
+ cppit != Option::cpp_ext.end(); ++cppit) {
+ if((*it).endsWith((*cppit))) {
+ d_file = (*it).left((*it).length() - (*cppit).length());
+ break;
+ }
+ }
+ }
+ if(!d_file.isEmpty()) {
+ d_file = odir + ".deps/" + d_file + ".d";
+ QStringList deps = findDependencies((*it)).filter(QRegExp(Option::cpp_moc_ext + "$"));
+ if(!deps.isEmpty())
+ t << d_file << ": " << deps.join(" ") << endl;
+ t << "-include " << d_file << endl;
+ project->values("QMAKE_DISTCLEAN") += d_file;
+ }
+ }
+ }
+ }
+ }
+
+ t << "####### Build rules" << endl << endl;
+ if(!project->values("SUBLIBS").isEmpty()) {
+ QString libdir = "tmp/";
+ if(!project->isEmpty("SUBLIBS_DIR"))
+ libdir = project->first("SUBLIBS_DIR");
+ t << "SUBLIBS = ";
+ QStringList &l = project->values("SUBLIBS");
+ for(QStringList::Iterator it = l.begin(); it != l.end(); ++it)
+ t << libdir << "lib" << (*it) << ".a ";
+ t << endl << endl;
+ }
+ if(project->isActiveConfig("depend_prl") && !project->isEmpty("QMAKE_PRL_INTERNAL_FILES")) {
+ QStringList &l = project->values("QMAKE_PRL_INTERNAL_FILES");
+ QStringList::Iterator it;
+ for(it = l.begin(); it != l.end(); ++it) {
+ QMakeMetaInfo libinfo;
+ if(libinfo.readLib((*it)) && !libinfo.isEmpty("QMAKE_PRL_BUILD_DIR")) {
+ QString dir;
+ int slsh = (*it).lastIndexOf(Option::dir_sep);
+ if(slsh != -1)
+ dir = (*it).left(slsh + 1);
+ QString targ = dir + libinfo.first("QMAKE_PRL_TARGET");
+ target_deps += " " + targ;
+ t << targ << ":" << "\n\t"
+ << "@echo \"Creating '" << targ << "'\"" << "\n\t"
+ << "(cd " << libinfo.first("QMAKE_PRL_BUILD_DIR") << ";"
+ << "$(MAKE))" << endl;
+ }
+ }
+ }
+ if(!project->values("QMAKE_APP_FLAG").isEmpty()) {
+ QString destdir = project->first("DESTDIR");
+ if(!project->isEmpty("QMAKE_BUNDLE")) {
+ QString bundle_loc = project->first("QMAKE_BUNDLE_LOCATION");
+ if(!bundle_loc.isEmpty() && !bundle_loc.startsWith("/"))
+ bundle_loc.prepend("/");
+ if(!bundle_loc.endsWith("/"))
+ bundle_loc += "/";
+ destdir += project->first("QMAKE_BUNDLE") + bundle_loc;
+ }
+ if(do_incremental) {
+ //incremental target
+ QString incr_target = var("TARGET") + "_incremental";
+ if(incr_target.indexOf(Option::dir_sep) != -1)
+ incr_target = incr_target.right(incr_target.length() -
+ (incr_target.lastIndexOf(Option::dir_sep) + 1));
+ QString incr_deps, incr_objs;
+ if(project->first("QMAKE_INCREMENTAL_STYLE") == "ld") {
+ QString incr_target_dir = var("OBJECTS_DIR") + incr_target + Option::obj_ext;
+ //actual target
+ t << incr_target_dir << ": $(OBJECTS)" << "\n\t"
+ << "ld -r -o "<< incr_target_dir << " $(OBJECTS)" << endl;
+ //communicated below
+ deps.prepend(incr_target_dir + " ");
+ incr_deps = "$(INCREMENTAL_OBJECTS)";
+ if(!incr_objs.isEmpty())
+ incr_objs += " ";
+ incr_objs += incr_target_dir;
+ } else {
+ //actual target
+ QString incr_target_dir = var("DESTDIR") + "lib" + incr_target + "." +
+ project->values("QMAKE_EXTENSION_SHLIB").first();
+ QString incr_lflags = var("QMAKE_LFLAGS_SHLIB") + " ";
+ if(project->isActiveConfig("debug"))
+ incr_lflags += var("QMAKE_LFLAGS_DEBUG");
+ else
+ incr_lflags += var("QMAKE_LFLAGS_RELEASE");
+ t << incr_target_dir << ": $(INCREMENTAL_OBJECTS)" << "\n\t";
+ if(!destdir.isEmpty())
+ t << "\n\t" << mkdir_p_asstring(destdir) << "\n\t";
+ t << "$(LINK) " << incr_lflags << " -o "<< incr_target_dir <<
+ " $(INCREMENTAL_OBJECTS)" << endl;
+ //communicated below
+ if(!destdir.isEmpty()) {
+ if(!incr_objs.isEmpty())
+ incr_objs += " ";
+ incr_objs += "-L" + destdir;
+ } else {
+ if(!incr_objs.isEmpty())
+ incr_objs += " ";
+ incr_objs += "-L" + qmake_getpwd();
+ }
+ if(!incr_objs.isEmpty())
+ incr_objs += " ";
+ incr_objs += " -l" + incr_target;
+ deps.prepend(incr_target_dir + " ");
+ incr_deps = "$(OBJECTS)";
+ }
+ t << "all: " << escapeDependencyPath(deps) << " " << valGlue(escapeDependencyPaths(project->values("ALL_DEPS")),""," "," ") << "$(TARGET)"
+ << endl << endl;
+
+ //real target
+ t << var("TARGET") << ": " << var("PRE_TARGETDEPS") << " " << incr_deps << " " << target_deps
+ << " " << var("POST_TARGETDEPS") << "\n\t";
+ if(!destdir.isEmpty())
+ t << "\n\t" << mkdir_p_asstring(destdir) << "\n\t";
+ if(!project->isEmpty("QMAKE_PRE_LINK"))
+ t << var("QMAKE_PRE_LINK") << "\n\t";
+ t << "$(LINK) $(LFLAGS) -o $(TARGET) " << incr_deps << " " << incr_objs << " $(OBJCOMP) $(LIBS)";
+ if(!project->isEmpty("QMAKE_POST_LINK"))
+ t << "\n\t" << var("QMAKE_POST_LINK");
+ t << endl << endl;
+ } else {
+ t << "all: " << escapeDependencyPath(deps) << " " << valGlue(escapeDependencyPaths(project->values("ALL_DEPS")),""," "," ") << "$(TARGET)"
+ << endl << endl;
+
+ t << "$(TARGET): " << var("PRE_TARGETDEPS") << " $(OBJECTS) "
+ << target_deps << " " << var("POST_TARGETDEPS") << "\n\t";
+ if(!destdir.isEmpty())
+ t << mkdir_p_asstring(destdir) << "\n\t";
+ if(!project->isEmpty("QMAKE_PRE_LINK"))
+ t << var("QMAKE_PRE_LINK") << "\n\t";
+ t << "$(LINK) $(LFLAGS) -o $(TARGET) $(OBJECTS) $(OBJCOMP) $(LIBS)";
+ if(!project->isEmpty("QMAKE_POST_LINK"))
+ t << "\n\t" << var("QMAKE_POST_LINK");
+ t << endl << endl;
+ }
+ } else if(!project->isActiveConfig("staticlib")) {
+ QString destdir = unescapeFilePath(project->first("DESTDIR")), incr_deps;
+ if(!project->isEmpty("QMAKE_BUNDLE")) {
+ QString bundle_loc = project->first("QMAKE_BUNDLE_LOCATION");
+ if(!bundle_loc.isEmpty() && !bundle_loc.startsWith("/"))
+ bundle_loc.prepend("/");
+ if(!bundle_loc.endsWith("/"))
+ bundle_loc += "/";
+ destdir += project->first("QMAKE_BUNDLE") + bundle_loc;
+ }
+ destdir = escapeFilePath(destdir);
+
+ if(do_incremental) {
+ QString s_ext = project->values("QMAKE_EXTENSION_SHLIB").first();
+ QString incr_target = var("QMAKE_ORIG_TARGET").replace(
+ QRegExp("\\." + s_ext), "").replace(QRegExp("^lib"), "") + "_incremental";
+ if(incr_target.indexOf(Option::dir_sep) != -1)
+ incr_target = incr_target.right(incr_target.length() -
+ (incr_target.lastIndexOf(Option::dir_sep) + 1));
+ incr_target = escapeFilePath(incr_target);
+
+ if(project->first("QMAKE_INCREMENTAL_STYLE") == "ld") {
+ QString incr_target_dir = escapeFilePath(var("OBJECTS_DIR") + incr_target + Option::obj_ext);
+ //actual target
+ const QString link_deps = "$(OBJECTS) ";
+ t << incr_target_dir << ": " << link_deps << "\n\t"
+ << "ld -r -o " << incr_target_dir << " " << link_deps << endl;
+ //communicated below
+ QStringList &cmd = project->values("QMAKE_LINK_SHLIB_CMD");
+ cmd.first().replace("$(OBJECTS) ", "$(INCREMENTAL_OBJECTS)"); //ick
+ cmd.append(incr_target_dir);
+ deps.prepend(incr_target_dir + " ");
+ incr_deps = "$(INCREMENTAL_OBJECTS)";
+ } else {
+ //actual target
+ QString incr_target_dir = escapeFilePath(destdir + "lib" + incr_target + "." + s_ext);
+ QString incr_lflags = var("QMAKE_LFLAGS_SHLIB") + " ";
+ if(!project->isEmpty("QMAKE_LFLAGS_INCREMENTAL"))
+ incr_lflags += var("QMAKE_LFLAGS_INCREMENTAL") + " ";
+ if(project->isActiveConfig("debug"))
+ incr_lflags += var("QMAKE_LFLAGS_DEBUG");
+ else
+ incr_lflags += var("QMAKE_LFLAGS_RELEASE");
+ t << incr_target_dir << ": $(INCREMENTAL_OBJECTS)" << "\n\t";
+ if(!destdir.isEmpty())
+ t << mkdir_p_asstring(destdir) << "\n\t";
+ t << "$(LINK) " << incr_lflags << " -o "<< incr_target_dir <<
+ " $(INCREMENTAL_OBJECTS)" << endl;
+ //communicated below
+ QStringList &cmd = project->values("QMAKE_LINK_SHLIB_CMD");
+ if(!destdir.isEmpty())
+ cmd.append(" -L" + destdir);
+ cmd.append(" -l" + incr_target);
+ deps.prepend(incr_target_dir + " ");
+ incr_deps = "$(OBJECTS)";
+ }
+
+ t << "all: " << " " << escapeDependencyPath(deps) << " " << valGlue(escapeDependencyPaths(project->values("ALL_DEPS")),""," "," ")
+ << " " << destdir << "$(TARGET)" << endl << endl;
+
+ //real target
+ t << destdir << "$(TARGET): " << var("PRE_TARGETDEPS") << " "
+ << incr_deps << " $(SUBLIBS) " << target_deps << " " << var("POST_TARGETDEPS");
+ } else {
+ t << "all: " << escapeDependencyPath(deps) << " " << valGlue(escapeDependencyPaths(project->values("ALL_DEPS")),""," "," ") << " " <<
+ destdir << "$(TARGET)" << endl << endl;
+ t << destdir << "$(TARGET): " << var("PRE_TARGETDEPS")
+ << " $(OBJECTS) $(SUBLIBS) $(OBJCOMP) " << target_deps
+ << " " << var("POST_TARGETDEPS");
+ }
+ if(!destdir.isEmpty())
+ t << "\n\t" << mkdir_p_asstring(destdir);
+ if(!project->isEmpty("QMAKE_PRE_LINK"))
+ t << "\n\t" << var("QMAKE_PRE_LINK");
+
+ if(project->isActiveConfig("compile_libtool")) {
+ t << "\n\t"
+ << var("QMAKE_LINK_SHLIB_CMD");
+ } else if(project->isActiveConfig("plugin")) {
+ t << "\n\t"
+ << "-$(DEL_FILE) $(TARGET)" << "\n\t"
+ << var("QMAKE_LINK_SHLIB_CMD");
+ if(!destdir.isEmpty())
+ t << "\n\t"
+ << "-$(MOVE) $(TARGET) " << destdir;
+ if(!project->isEmpty("QMAKE_POST_LINK"))
+ t << "\n\t" << var("QMAKE_POST_LINK") << "\n\t";
+ t << endl << endl;
+ } else if(!project->isEmpty("QMAKE_BUNDLE")) {
+ t << "\n\t"
+ << "-$(DEL_FILE) $(TARGET) $(TARGET0) $(DESTDIR)$(TARGET0)" << "\n\t"
+ << var("QMAKE_LINK_SHLIB_CMD") << "\n\t"
+ << mkdir_p_asstring("\"`dirname $(DESTDIR)$(TARGETD)`\"", false) << "\n\t"
+ << "-$(MOVE) $(TARGET) $(DESTDIR)$(TARGETD)" << "\n\t"
+ << mkdir_p_asstring("\"`dirname $(DESTDIR)$(TARGET0)`\"", false) << "\n\t"
+ << varGlue("QMAKE_LN_SHLIB","-"," "," Versions/" +
+ project->first("QMAKE_FRAMEWORK_VERSION") +
+ "/$(TARGET) $(DESTDIR)$(TARGET0)") << "\n\t"
+ << "-$(DEL_FILE) " << destdir << "Versions/Current" << "\n\t"
+ << varGlue("QMAKE_LN_SHLIB","-"," ", " " + project->first("QMAKE_FRAMEWORK_VERSION") +
+ " " + destdir + "Versions/Current") << "\n\t";
+ if(!project->isEmpty("QMAKE_POST_LINK"))
+ t << "\n\t" << var("QMAKE_POST_LINK");
+ t << endl << endl;
+ } else if(project->isEmpty("QMAKE_HPUX_SHLIB")) {
+ t << "\n\t"
+ << "-$(DEL_FILE) $(TARGET) $(TARGET0) $(TARGET1) $(TARGET2)" << "\n\t"
+ << var("QMAKE_LINK_SHLIB_CMD") << "\n\t";
+ t << varGlue("QMAKE_LN_SHLIB","-"," "," $(TARGET) $(TARGET0)") << "\n\t"
+ << varGlue("QMAKE_LN_SHLIB","-"," "," $(TARGET) $(TARGET1)") << "\n\t"
+ << varGlue("QMAKE_LN_SHLIB","-"," "," $(TARGET) $(TARGET2)");
+ if(!destdir.isEmpty())
+ t << "\n\t"
+ << "-$(DEL_FILE) " << destdir << "$(TARGET)\n\t"
+ << "-$(DEL_FILE) " << destdir << "$(TARGET0)\n\t"
+ << "-$(DEL_FILE) " << destdir << "$(TARGET1)\n\t"
+ << "-$(DEL_FILE) " << destdir << "$(TARGET2)\n\t"
+ << "-$(MOVE) $(TARGET) $(TARGET0) $(TARGET1) $(TARGET2) " << destdir;
+ if(!project->isEmpty("QMAKE_POST_LINK"))
+ t << "\n\t" << var("QMAKE_POST_LINK");
+ t << endl << endl;
+ } else {
+ t << "\n\t"
+ << "-$(DEL_FILE) $(TARGET) $(TARGET0)" << "\n\t"
+ << var("QMAKE_LINK_SHLIB_CMD") << "\n\t";
+ t << varGlue("QMAKE_LN_SHLIB",""," "," $(TARGET) $(TARGET0)");
+ if(!destdir.isEmpty())
+ t << "\n\t"
+ << "-$(DEL_FILE) " << destdir << "$(TARGET)\n\t"
+ << "-$(DEL_FILE) " << destdir << "$(TARGET0)\n\t"
+ << "-$(MOVE) $(TARGET) $(TARGET0) " << destdir;
+ if(!project->isEmpty("QMAKE_POST_LINK"))
+ t << "\n\t" << var("QMAKE_POST_LINK");
+ t << endl << endl;
+ }
+ t << endl << endl;
+
+ if (! project->isActiveConfig("plugin")) {
+ t << "staticlib: $(TARGETA)" << endl << endl;
+ t << "$(TARGETA): " << var("PRE_TARGETDEPS") << " $(OBJECTS) $(OBJCOMP)";
+ if(do_incremental)
+ t << " $(INCREMENTAL_OBJECTS)";
+ t << " " << var("POST_TARGETDEPS") << "\n\t"
+ << "-$(DEL_FILE) $(TARGETA) " << "\n\t"
+ << var("QMAKE_AR_CMD");
+ if(do_incremental)
+ t << " $(INCREMENTAL_OBJECTS)";
+ if(!project->isEmpty("QMAKE_RANLIB"))
+ t << "\n\t" << "$(RANLIB) $(TARGETA)";
+ t << endl << endl;
+ }
+ } else {
+ QString destdir = project->first("DESTDIR");
+ t << "all: " << escapeDependencyPath(deps) << " " << valGlue(escapeDependencyPaths(project->values("ALL_DEPS")),""," "," ") << destdir << "$(TARGET) "
+ << varGlue("QMAKE_AR_SUBLIBS", destdir, " " + destdir, "") << "\n\n"
+ << "staticlib: " << destdir << "$(TARGET)" << "\n\n";
+ if(project->isEmpty("QMAKE_AR_SUBLIBS")) {
+ t << destdir << "$(TARGET): " << var("PRE_TARGETDEPS")
+ << " $(OBJECTS) $(OBJCOMP) " << var("POST_TARGETDEPS") << "\n\t";
+ if(!destdir.isEmpty())
+ t << mkdir_p_asstring(destdir) << "\n\t";
+ t << "-$(DEL_FILE) $(TARGET)" << "\n\t"
+ << var("QMAKE_AR_CMD") << "\n";
+ if(!project->isEmpty("QMAKE_POST_LINK"))
+ t << "\t" << var("QMAKE_POST_LINK") << "\n";
+ if(!project->isEmpty("QMAKE_RANLIB"))
+ t << "\t" << "$(RANLIB) $(TARGET)" << "\n";
+ if(!destdir.isEmpty())
+ t << "\t" << "-$(DEL_FILE) " << destdir << "$(TARGET)" << "\n"
+ << "\t" << "-$(MOVE) $(TARGET) " << destdir << "\n";
+ } else {
+ int max_files = project->first("QMAKE_MAX_FILES_PER_AR").toInt();
+ QStringList objs = project->values("OBJECTS") + project->values("OBJCOMP"),
+ libs = project->values("QMAKE_AR_SUBLIBS");
+ libs.prepend("$(TARGET)");
+ for(QStringList::Iterator libit = libs.begin(), objit = objs.begin();
+ libit != libs.end(); ++libit) {
+ QStringList build;
+ for(int cnt = 0; cnt < max_files && objit != objs.end(); ++objit, cnt++)
+ build << (*objit);
+ QString ar;
+ if((*libit) == "$(TARGET)") {
+ t << destdir << "$(TARGET): " << var("PRE_TARGETDEPS")
+ << " " << var("POST_TARGETDEPS") << valList(build) << "\n\t";
+ ar = project->values("QMAKE_AR_CMD").first();
+ ar = ar.replace("$(OBJECTS)", build.join(" "));
+ } else {
+ t << (*libit) << ": " << valList(build) << "\n\t";
+ ar = "$(AR) " + (*libit) + " " + build.join(" ");
+ }
+ if(!destdir.isEmpty())
+ t << mkdir_p_asstring(destdir) << "\n\t";
+ t << "-$(DEL_FILE) " << (*libit) << "\n\t"
+ << ar << "\n";
+ if(!project->isEmpty("QMAKE_POST_LINK"))
+ t << "\t" << var("QMAKE_POST_LINK") << "\n";
+ if(!project->isEmpty("QMAKE_RANLIB"))
+ t << "\t" << "$(RANLIB) " << (*libit) << "\n";
+ if(!destdir.isEmpty())
+ t << "\t" << "-$(DEL_FILE) " << destdir << (*libit) << "\n"
+ << "\t" << "-$(MOVE) " << (*libit) << " " << destdir << "\n";
+ }
+ }
+ t << endl << endl;
+ }
+
+ writeMakeQmake(t);
+ if(project->isEmpty("QMAKE_FAILED_REQUIREMENTS") && !project->isActiveConfig("no_autoqmake")) {
+ QString meta_files;
+ if(project->isActiveConfig("create_libtool") && project->first("TEMPLATE") == "lib" &&
+ !project->isActiveConfig("compile_libtool")) { //libtool
+ if(!meta_files.isEmpty())
+ meta_files += " ";
+ meta_files += libtoolFileName();
+ }
+ if(project->isActiveConfig("create_pc") && project->first("TEMPLATE") == "lib") { //pkg-config
+ if(!meta_files.isEmpty())
+ meta_files += " ";
+ meta_files += pkgConfigFileName();
+ }
+ if(!meta_files.isEmpty())
+ t << escapeDependencyPath(meta_files) << ": " << "\n\t"
+ << "@$(QMAKE) -prl " << buildArgs() << " " << project->projectFile() << endl;
+ }
+
+ if(!project->first("QMAKE_PKGINFO").isEmpty()) {
+ QString pkginfo = escapeFilePath(project->first("QMAKE_PKGINFO"));
+ QString destdir = escapeFilePath(project->first("DESTDIR") + project->first("QMAKE_BUNDLE") + "/Contents");
+ t << pkginfo << ": " << "\n\t";
+ if(!destdir.isEmpty())
+ t << mkdir_p_asstring(destdir) << "\n\t";
+ t << "@$(DEL_FILE) " << pkginfo << "\n\t"
+ << "@echo \"APPL"
+ << (project->isEmpty("QMAKE_PKGINFO_TYPEINFO") ? QString::fromLatin1("????") : project->first("QMAKE_PKGINFO_TYPEINFO").left(4))
+ << "\" >" << pkginfo << endl;
+ }
+ if(!project->first("QMAKE_BUNDLE_RESOURCE_FILE").isEmpty()) {
+ QString resources = escapeFilePath(project->first("QMAKE_BUNDLE_RESOURCE_FILE"));
+ QString destdir = escapeFilePath(project->first("DESTDIR") + project->first("QMAKE_BUNDLE") + "/Contents/Resources");
+ t << resources << ": " << "\n\t";
+ t << mkdir_p_asstring(destdir) << "\n\t";
+ t << "@touch " << resources << "\n\t" << endl;
+ }
+ if(!project->isEmpty("QMAKE_BUNDLE")) {
+ //copy the plist
+ QString info_plist = escapeFilePath(fileFixify(project->first("QMAKE_INFO_PLIST"))),
+ info_plist_out = escapeFilePath(project->first("QMAKE_INFO_PLIST_OUT"));
+ QString destdir = info_plist_out.section(Option::dir_sep, 0, -2);
+ t << info_plist_out << ": " << "\n\t";
+ if(!destdir.isEmpty())
+ t << mkdir_p_asstring(destdir) << "\n\t";
+ if(project->first("TEMPLATE") == "app") {
+ QString icon = fileFixify(var("ICON"));
+ t << "@$(DEL_FILE) " << info_plist_out << "\n\t"
+ << "@sed "
+ << "-e \"s,@ICON@," << icon.section(Option::dir_sep, -1) << ",g\" "
+ << "-e \"s,@EXECUTABLE@," << var("QMAKE_ORIG_TARGET") << ",g\" "
+ << "-e \"s,@TYPEINFO@,"<< (project->isEmpty("QMAKE_PKGINFO_TYPEINFO") ?
+ QString::fromLatin1("????") : project->first("QMAKE_PKGINFO_TYPEINFO").left(4)) << ",g\" "
+ << "" << info_plist << " >" << info_plist_out << endl;
+ //copy the icon
+ if(!project->isEmpty("ICON")) {
+ QString dir = project->first("DESTDIR") + project->first("QMAKE_BUNDLE") + "/Contents/Resources/";
+ const QString icon_path = escapeFilePath(dir + icon.section(Option::dir_sep, -1));
+ t << icon_path << ": " << icon << "\n\t"
+ << mkdir_p_asstring(dir) << "\n\t"
+ << "@$(DEL_FILE) " << icon_path << "\n\t"
+ << "@$(COPY_FILE) " << escapeFilePath(icon) << " " << icon_path << endl;
+ }
+ } else {
+ t << "@$(DEL_FILE) " << info_plist_out << "\n\t"
+ << "@sed "
+ << "-e \"s,@LIBRARY@," << var("QMAKE_ORIG_TARGET") << ",g\" "
+ << "-e \"s,@SHORT_VERSION@," << project->first("VER_MAJ") << "." << project->first("VER_MIN") << ",g\" "
+ << "-e \"s,@TYPEINFO@,"
+ << (project->isEmpty("QMAKE_PKGINFO_TYPEINFO") ?
+ QString::fromLatin1("????") : project->first("QMAKE_PKGINFO_TYPEINFO").left(4)) << ",g\" "
+ << "" << info_plist << " >" << info_plist_out << endl;
+ }
+ //copy other data
+ if(!project->isEmpty("QMAKE_BUNDLE_DATA")) {
+ QString bundle_dir = project->first("DESTDIR") + project->first("QMAKE_BUNDLE") + "/";
+ const QStringList &bundle_data = project->values("QMAKE_BUNDLE_DATA");
+ for(int i = 0; i < bundle_data.count(); i++) {
+ const QStringList &files = project->values(bundle_data[i] + ".files");
+ QString path = bundle_dir;
+ if(!project->isEmpty(bundle_data[i] + ".version")) {
+ QString version = project->first(bundle_data[i] + ".version") + "/" +
+ project->first("QMAKE_FRAMEWORK_VERSION") + "/";
+ t << Option::fixPathToLocalOS(path + project->first(bundle_data[i] + ".path")) << ": " << "\n\t"
+ << mkdir_p_asstring(path) << "\n\t"
+ << "@$(SYMLINK) " << version << project->first(bundle_data[i] + ".path") << " " << path << endl;
+ path += version;
+ }
+ path += project->first(bundle_data[i] + ".path");
+ path = Option::fixPathToLocalOS(path);
+ for(int file = 0; file < files.count(); file++) {
+ QString src = fileFixify(files[file], FileFixifyAbsolute);
+ if (!QFile::exists(src))
+ src = files[file];
+ src = escapeFilePath(src);
+ const QString dst = escapeFilePath(path + Option::dir_sep + fileInfo(files[file]).fileName());
+ t << dst << ": " << src << "\n\t"
+ << mkdir_p_asstring(path) << "\n\t";
+ QFileInfo fi(fileInfo(files[file]));
+ if(fi.isDir())
+ t << "@$(DEL_FILE) -r " << dst << "\n\t"
+ << "@$(COPY_DIR) " << src << " " << dst << endl;
+ else
+ t << "@$(DEL_FILE) " << dst << "\n\t"
+ << "@$(COPY_FILE) " << src << " " << dst << endl;
+ }
+ }
+ }
+ }
+
+ QString ddir;
+ QString packageName(project->first("QMAKE_ORIG_TARGET"));
+ if(!project->isActiveConfig("no_dist_version"))
+ packageName += var("VERSION");
+ if (project->isEmpty("QMAKE_DISTDIR"))
+ ddir = packageName;
+ else
+ ddir = project->first("QMAKE_DISTDIR");
+
+ QString ddir_c = escapeFilePath(fileFixify((project->isEmpty("OBJECTS_DIR") ? QString(".tmp/") :
+ project->first("OBJECTS_DIR")) + ddir));
+ t << "dist: " << "\n\t"
+ << mkdir_p_asstring(ddir_c) << "\n\t"
+ << "$(COPY_FILE) --parents $(SOURCES) $(DIST) " << ddir_c << Option::dir_sep << " && ";
+ if(!project->isEmpty("QMAKE_EXTRA_COMPILERS")) {
+ const QStringList &quc = project->values("QMAKE_EXTRA_COMPILERS");
+ for(QStringList::ConstIterator it = quc.begin(); it != quc.end(); ++it) {
+ const QStringList &var = project->values((*it)+".input");
+ for(QStringList::ConstIterator var_it = var.begin(); var_it != var.end(); ++var_it) {
+ const QStringList &val = project->values((*var_it));
+ if(val.isEmpty())
+ continue;
+ t << "$(COPY_FILE) --parents " << val.join(" ") << " " << ddir_c << Option::dir_sep << " && ";
+ }
+ }
+ }
+ if(!project->isEmpty("TRANSLATIONS"))
+ t << "$(COPY_FILE) --parents " << var("TRANSLATIONS") << " " << ddir_c << Option::dir_sep << " && ";
+ t << "(cd `dirname " << ddir_c << "` && "
+ << "$(TAR) " << packageName << ".tar " << ddir << " && "
+ << "$(COMPRESS) " << packageName << ".tar) && "
+ << "$(MOVE) `dirname " << ddir_c << "`" << Option::dir_sep << packageName << ".tar.gz . && "
+ << "$(DEL_FILE) -r " << ddir_c
+ << endl << endl;
+
+ t << endl;
+
+ QString clean_targets = "compiler_clean " + var("CLEAN_DEPS");
+ if(do_incremental) {
+ t << "incrclean:" << "\n";
+ if(src_incremental)
+ t << "\t-$(DEL_FILE) $(INCREMENTAL_OBJECTS)" << "\n";
+ t << endl;
+ }
+
+ t << "clean:" << clean_targets << "\n\t";
+ if(!project->isEmpty("OBJECTS")) {
+ if(project->isActiveConfig("compile_libtool"))
+ t << "-$(LIBTOOL) --mode=clean $(DEL_FILE) $(OBJECTS)" << "\n\t";
+ else
+ t << "-$(DEL_FILE) $(OBJECTS)" << "\n\t";
+ }
+ if(doPrecompiledHeaders() && !project->isEmpty("PRECOMPILED_HEADER")) {
+ QStringList precomp_files;
+ QString precomph_out_dir;
+
+ if(!project->isEmpty("PRECOMPILED_DIR"))
+ precomph_out_dir = project->first("PRECOMPILED_DIR");
+ precomph_out_dir += project->first("QMAKE_ORIG_TARGET") + project->first("QMAKE_PCH_OUTPUT_EXT");
+
+ if (project->isActiveConfig("icc_pch_style")) {
+ // icc style
+ QString pchBaseName = project->first("QMAKE_ORIG_TARGET");
+ QString pchOutput;
+ if(!project->isEmpty("PRECOMPILED_DIR"))
+ pchOutput = project->first("PRECOMPILED_DIR");
+ pchOutput += pchBaseName + project->first("QMAKE_PCH_OUTPUT_EXT");
+ QString sourceFile = pchOutput + Option::cpp_ext.first();
+ QString objectFile = createObjectList(QStringList(sourceFile)).first();
+
+ precomp_files << precomph_out_dir << sourceFile << objectFile;
+ } else {
+ // gcc style
+ precomph_out_dir += Option::dir_sep;
+
+ QString header_prefix = project->first("QMAKE_PRECOMP_PREFIX");
+ if(!project->isEmpty("QMAKE_CFLAGS_PRECOMPILE"))
+ precomp_files += precomph_out_dir + header_prefix + "c";
+ if(!project->isEmpty("QMAKE_CXXFLAGS_PRECOMPILE"))
+ precomp_files += precomph_out_dir + header_prefix + "c++";
+ if(project->isActiveConfig("objective_c")) {
+ if(!project->isEmpty("QMAKE_OBJCFLAGS_PRECOMPILE"))
+ precomp_files += precomph_out_dir + header_prefix + "objective-c";
+ if(!project->isEmpty("QMAKE_OBJCXXFLAGS_PRECOMPILE"))
+ precomp_files += precomph_out_dir + header_prefix + "objective-c++";
+ }
+ }
+ t << "-$(DEL_FILE) " << precomp_files.join(" ") << "\n\t";
+ }
+ if(!project->isEmpty("IMAGES"))
+ t << varGlue("QMAKE_IMAGE_COLLECTION", "\t-$(DEL_FILE) ", " ", "") << "\n\t";
+ if(src_incremental)
+ t << "-$(DEL_FILE) $(INCREMENTAL_OBJECTS)" << "\n\t";
+ t << varGlue("QMAKE_CLEAN","-$(DEL_FILE) "," ","\n\t")
+ << "-$(DEL_FILE) *~ core *.core" << "\n"
+ << varGlue("CLEAN_FILES","\t-$(DEL_FILE) "," ","") << endl << endl;
+ t << "####### Sub-libraries" << endl << endl;
+ if (!project->values("SUBLIBS").isEmpty()) {
+ QString libdir = "tmp/";
+ if(!project->isEmpty("SUBLIBS_DIR"))
+ libdir = project->first("SUBLIBS_DIR");
+ QStringList &l = project->values("SUBLIBS");
+ for(it = l.begin(); it != l.end(); ++it)
+ t << libdir << "lib" << (*it) << ".a" << ":\n\t"
+ << var(QString("MAKELIB") + (*it)) << endl << endl;
+ }
+
+ QString destdir = project->first("DESTDIR");
+ if(!destdir.isEmpty() && destdir.right(1) != Option::dir_sep)
+ destdir += Option::dir_sep;
+ t << "distclean: " << "clean\n";
+ if(!project->isEmpty("QMAKE_BUNDLE")) {
+ QString bundlePath = escapeFilePath(destdir + project->first("QMAKE_BUNDLE"));
+ t << "\t-$(DEL_FILE) -r " << bundlePath << endl;
+ } else if(project->isActiveConfig("compile_libtool")) {
+ t << "\t-$(LIBTOOL) --mode=clean $(DEL_FILE) " << "$(TARGET)" << endl;
+ } else if(!project->isActiveConfig("staticlib") && project->values("QMAKE_APP_FLAG").isEmpty() &&
+ !project->isActiveConfig("plugin")) {
+ t << "\t-$(DEL_FILE) " << destdir << "$(TARGET)" << " " << endl
+ << "\t-$(DEL_FILE) " << destdir << "$(TARGET0) " << destdir << "$(TARGET1) "
+ << destdir << "$(TARGET2) $(TARGETA)" << endl;
+ } else {
+ t << "\t-$(DEL_FILE) " << "$(TARGET)" << " " << endl;
+ }
+ t << varGlue("QMAKE_DISTCLEAN","\t-$(DEL_FILE) "," ","\n");
+ {
+ QString ofile = Option::fixPathToTargetOS(fileFixify(Option::output.fileName()));
+ if(!ofile.isEmpty())
+ t << "\t-$(DEL_FILE) " << ofile << endl;
+ }
+ t << endl << endl;
+
+ if(doPrecompiledHeaders() && !project->isEmpty("PRECOMPILED_HEADER")) {
+ QString pchInput = project->first("PRECOMPILED_HEADER");
+ t << "###### Prefix headers" << endl;
+ QString comps[] = { "C", "CXX", "OBJC", "OBJCXX", QString() };
+ for(int i = 0; !comps[i].isNull(); i++) {
+ QString pchFlags = var("QMAKE_" + comps[i] + "FLAGS_PRECOMPILE");
+ if(pchFlags.isEmpty())
+ continue;
+
+ QString cflags;
+ if(comps[i] == "OBJC" || comps[i] == "OBJCXX")
+ cflags += " $(CFLAGS)";
+ else
+ cflags += " $(" + comps[i] + "FLAGS)";
+
+ QString pchBaseName = project->first("QMAKE_ORIG_TARGET");
+ QString pchOutput;
+ if(!project->isEmpty("PRECOMPILED_DIR"))
+ pchOutput = project->first("PRECOMPILED_DIR");
+ pchOutput += pchBaseName + project->first("QMAKE_PCH_OUTPUT_EXT");
+
+ if (project->isActiveConfig("icc_pch_style")) {
+ // icc style
+ QString sourceFile = pchOutput + Option::cpp_ext.first();
+ QString objectFile = createObjectList(QStringList(sourceFile)).first();
+ t << pchOutput << ": " << pchInput << " " << findDependencies(pchInput).join(" \\\n\t\t")
+ << "\n\techo \"// Automatically generated, do not modify\" > " << sourceFile
+ << "\n\trm -f " << pchOutput;
+
+ pchFlags = pchFlags.replace("${QMAKE_PCH_TEMP_SOURCE}", sourceFile)
+ .replace("${QMAKE_PCH_TEMP_OBJECT}", objectFile);
+ } else {
+ // gcc style
+ QString header_prefix = project->first("QMAKE_PRECOMP_PREFIX");
+
+ pchOutput += Option::dir_sep;
+ QString pchOutputDir = pchOutput, pchOutputFile;
+
+ if(comps[i] == "C") {
+ pchOutputFile = "c";
+ } else if(comps[i] == "CXX") {
+ pchOutputFile = "c++";
+ } else if(project->isActiveConfig("objective_c")) {
+ if(comps[i] == "OBJC")
+ pchOutputFile = "objective-c";
+ else if(comps[i] == "OBJCXX")
+ pchOutputFile = "objective-c++";
+ }
+ if(pchOutputFile.isEmpty())
+ continue;
+ pchOutput += header_prefix + pchOutputFile;
+
+ t << pchOutput << ": " << pchInput << " " << findDependencies(pchInput).join(" \\\n\t\t")
+ << "\n\t" << mkdir_p_asstring(pchOutputDir);
+ }
+ pchFlags = pchFlags.replace("${QMAKE_PCH_INPUT}", pchInput)
+ .replace("${QMAKE_PCH_OUTPUT_BASE}", pchBaseName)
+ .replace("${QMAKE_PCH_OUTPUT}", pchOutput);
+
+ QString compiler;
+ if(comps[i] == "C" || comps[i] == "OBJC" || comps[i] == "OBJCXX")
+ compiler = "$(CC)";
+ else
+ compiler = "$(CXX)";
+
+ // compile command
+ t << "\n\t" << compiler << cflags << " $(INCPATH) " << pchFlags << endl << endl;
+ }
+ }
+
+ writeExtraTargets(t);
+ writeExtraCompilerTargets(t);
+}
+
+void UnixMakefileGenerator::init2()
+{
+ //version handling
+ if(project->isEmpty("VERSION"))
+ project->values("VERSION").append("1.0." +
+ (project->isEmpty("VER_PAT") ? QString("0") :
+ project->first("VER_PAT")));
+ QStringList l = project->first("VERSION").split('.');
+ l << "0" << "0"; //make sure there are three
+ project->values("VER_MAJ").append(l[0]);
+ project->values("VER_MIN").append(l[1]);
+ project->values("VER_PAT").append(l[2]);
+ if(project->isEmpty("QMAKE_FRAMEWORK_VERSION"))
+ project->values("QMAKE_FRAMEWORK_VERSION").append(project->values("VER_MAJ").first());
+
+ if (!project->values("QMAKE_APP_FLAG").isEmpty()) {
+ if(!project->isEmpty("QMAKE_BUNDLE")) {
+ QString bundle_loc = project->first("QMAKE_BUNDLE_LOCATION");
+ if(!bundle_loc.isEmpty() && !bundle_loc.startsWith("/"))
+ bundle_loc.prepend("/");
+ if(!bundle_loc.endsWith("/"))
+ bundle_loc += "/";
+ project->values("TARGET").first().prepend(project->first("QMAKE_BUNDLE") + bundle_loc);
+ }
+ if(!project->isEmpty("TARGET"))
+ project->values("TARGET").first().prepend(project->first("DESTDIR"));
+ if (!project->values("QMAKE_CYGWIN_EXE").isEmpty())
+ project->values("TARGET_EXT").append(".exe");
+ } else if (project->isActiveConfig("staticlib")) {
+ project->values("TARGET").first().prepend("lib");
+ project->values("TARGET").first() += ".a";
+ if(project->values("QMAKE_AR_CMD").isEmpty())
+ project->values("QMAKE_AR_CMD").append("$(AR) $(TARGET) $(OBJECTS)");
+ } else {
+ project->values("TARGETA").append(project->first("DESTDIR") + "lib" + project->first("TARGET") + ".a");
+ if(project->isActiveConfig("compile_libtool"))
+ project->values("TARGET_la") = QStringList(project->first("DESTDIR") + "lib" + project->first("TARGET") + Option::libtool_ext);
+
+ if (!project->values("QMAKE_AR_CMD").isEmpty())
+ project->values("QMAKE_AR_CMD").first().replace("(TARGET)","(TARGETA)");
+ else
+ project->values("QMAKE_AR_CMD").append("$(AR) $(TARGETA) $(OBJECTS)");
+ if(project->isActiveConfig("compile_libtool")) {
+ project->values("TARGET") = project->values("TARGET_la");
+ } else if(!project->isEmpty("QMAKE_BUNDLE")) {
+ QString bundle_loc = project->first("QMAKE_BUNDLE_LOCATION");
+ if(!bundle_loc.isEmpty() && !bundle_loc.startsWith("/"))
+ bundle_loc.prepend("/");
+ if(!bundle_loc.endsWith("/"))
+ bundle_loc += "/";
+ project->values("TARGET_").append(project->first("QMAKE_BUNDLE") +
+ bundle_loc + unescapeFilePath(project->first("TARGET")));
+ project->values("TARGET_x.y").append(project->first("QMAKE_BUNDLE") +
+ "/Versions/" +
+ project->first("QMAKE_FRAMEWORK_VERSION") +
+ bundle_loc + unescapeFilePath(project->first("TARGET")));
+ } else if(project->isActiveConfig("plugin")) {
+ QString prefix;
+ if(!project->isActiveConfig("no_plugin_name_prefix"))
+ prefix = "lib";
+ project->values("TARGET_x.y.z").append(prefix +
+ project->first("TARGET") + "." +
+ project->first("QMAKE_EXTENSION_PLUGIN"));
+ if(project->isActiveConfig("lib_version_first"))
+ project->values("TARGET_x").append(prefix + project->first("TARGET") + "." +
+ project->first("VER_MAJ") + "." +
+ project->first("QMAKE_EXTENSION_PLUGIN"));
+ else
+ project->values("TARGET_x").append(prefix + project->first("TARGET") + "." +
+ project->first("QMAKE_EXTENSION_PLUGIN") +
+ "." + project->first("VER_MAJ"));
+ project->values("TARGET") = project->values("TARGET_x.y.z");
+ } else if (!project->isEmpty("QMAKE_HPUX_SHLIB")) {
+ project->values("TARGET_").append("lib" + project->first("TARGET") + ".sl");
+ if(project->isActiveConfig("lib_version_first"))
+ project->values("TARGET_x").append("lib" + project->first("VER_MAJ") + "." +
+ project->first("TARGET"));
+ else
+ project->values("TARGET_x").append("lib" + project->first("TARGET") + "." +
+ project->first("VER_MAJ"));
+ project->values("TARGET") = project->values("TARGET_x");
+ } else if (!project->isEmpty("QMAKE_AIX_SHLIB")) {
+ project->values("TARGET_").append("lib" + project->first("TARGET") + ".a");
+ if(project->isActiveConfig("lib_version_first")) {
+ project->values("TARGET_x").append("lib" + project->first("TARGET") + "." +
+ project->first("VER_MAJ") + "." +
+ project->first("QMAKE_EXTENSION_SHLIB"));
+ project->values("TARGET_x.y").append("lib" + project->first("TARGET") + "." +
+ project->first("VER_MAJ") +
+ "." + project->first("VER_MIN") + "." +
+ project->first("QMAKE_EXTENSION_SHLIB"));
+ project->values("TARGET_x.y.z").append("lib" + project->first("TARGET") + "." +
+ project->first("VER_MAJ") + "." +
+ project->first("VER_MIN") + "." +
+ project->first("VER_PAT") + "." +
+ project->first("QMAKE_EXTENSION_SHLIB"));
+ } else {
+ project->values("TARGET_x").append("lib" + project->first("TARGET") + "." +
+ project->first("QMAKE_EXTENSION_SHLIB") +
+ "." + project->first("VER_MAJ"));
+ project->values("TARGET_x.y").append("lib" + project->first("TARGET") + "." +
+ project->first("QMAKE_EXTENSION_SHLIB") +
+ "." + project->first("VER_MAJ") +
+ "." + project->first("VER_MIN"));
+ project->values("TARGET_x.y.z").append("lib" + project->first("TARGET") + "." +
+ project->first("QMAKE_EXTENSION_SHLIB") + "." +
+ project->first("VER_MAJ") + "." +
+ project->first("VER_MIN") + "." +
+ project->first("VER_PAT"));
+ }
+ project->values("TARGET") = project->values("TARGET_x.y.z");
+ } else {
+ project->values("TARGET_").append("lib" + project->first("TARGET") + "." +
+ project->first("QMAKE_EXTENSION_SHLIB"));
+ if(project->isActiveConfig("lib_version_first")) {
+ project->values("TARGET_x").append("lib" + project->first("TARGET") + "." +
+ project->first("VER_MAJ") + "." +
+ project->first("QMAKE_EXTENSION_SHLIB"));
+ project->values("TARGET_x.y").append("lib" + project->first("TARGET") + "." +
+ project->first("VER_MAJ") +
+ "." + project->first("VER_MIN") + "." +
+ project->first("QMAKE_EXTENSION_SHLIB"));
+ project->values("TARGET_x.y.z").append("lib" + project->first("TARGET") + "." +
+ project->first("VER_MAJ") + "." +
+ project->first("VER_MIN") + "." +
+ project->first("VER_PAT") + "." +
+ project->values("QMAKE_EXTENSION_SHLIB").first());
+ } else {
+ project->values("TARGET_x").append("lib" + project->first("TARGET") + "." +
+ project->first("QMAKE_EXTENSION_SHLIB") +
+ "." + project->first("VER_MAJ"));
+ project->values("TARGET_x.y").append("lib" + project->first("TARGET") + "." +
+ project->first("QMAKE_EXTENSION_SHLIB")
+ + "." + project->first("VER_MAJ") +
+ "." + project->first("VER_MIN"));
+ project->values("TARGET_x.y.z").append("lib" + project->first("TARGET") +
+ "." +
+ project->values(
+ "QMAKE_EXTENSION_SHLIB").first() + "." +
+ project->first("VER_MAJ") + "." +
+ project->first("VER_MIN") + "." +
+ project->first("VER_PAT"));
+ }
+ project->values("TARGET") = project->values("TARGET_x.y.z");
+ }
+ if(project->isEmpty("QMAKE_LN_SHLIB"))
+ project->values("QMAKE_LN_SHLIB").append("ln -s");
+ if (!project->values("QMAKE_LFLAGS_SONAME").isEmpty()) {
+ QString soname;
+ if(project->isActiveConfig("plugin")) {
+ if(!project->values("TARGET").isEmpty())
+ soname += project->first("TARGET");
+ } else if(!project->isEmpty("QMAKE_BUNDLE")) {
+ soname += project->first("TARGET_x.y");
+ } else if(!project->values("TARGET_x").isEmpty()) {
+ soname += project->first("TARGET_x");
+ }
+ if(!soname.isEmpty()) {
+ if(project->isActiveConfig("absolute_library_soname") &&
+ project->values("INSTALLS").indexOf("target") != -1 &&
+ !project->isEmpty("target.path")) {
+ QString instpath = Option::fixPathToTargetOS(project->first("target.path"));
+ if(!instpath.endsWith(Option::dir_sep))
+ instpath += Option::dir_sep;
+ soname.prepend(instpath);
+ }
+ project->values("QMAKE_LFLAGS_SONAME").first() += escapeFilePath(soname);
+ }
+ }
+ if (project->values("QMAKE_LINK_SHLIB_CMD").isEmpty())
+ project->values("QMAKE_LINK_SHLIB_CMD").append(
+ "$(LINK) $(LFLAGS) -o $(TARGET) $(OBJECTS) $(LIBS) $(OBJCOMP)");
+ }
+ if (!project->values("QMAKE_APP_FLAG").isEmpty()) {
+ project->values("QMAKE_CFLAGS") += project->values("QMAKE_CFLAGS_APP");
+ project->values("QMAKE_CXXFLAGS") += project->values("QMAKE_CXXFLAGS_APP");
+ project->values("QMAKE_LFLAGS") += project->values("QMAKE_LFLAGS_APP");
+ } else if (project->isActiveConfig("dll")) {
+ if(!project->isActiveConfig("plugin") || !project->isActiveConfig("plugin_no_share_shlib_cflags")) {
+ project->values("QMAKE_CFLAGS") += project->values("QMAKE_CFLAGS_SHLIB");
+ project->values("QMAKE_CXXFLAGS") += project->values("QMAKE_CXXFLAGS_SHLIB");
+ }
+ if (project->isActiveConfig("plugin")) {
+ project->values("QMAKE_CFLAGS") += project->values("QMAKE_CFLAGS_PLUGIN");
+ project->values("QMAKE_CXXFLAGS") += project->values("QMAKE_CXXFLAGS_PLUGIN");
+ project->values("QMAKE_LFLAGS") += project->values("QMAKE_LFLAGS_PLUGIN");
+ if(project->isActiveConfig("plugin_with_soname") && !project->isActiveConfig("compile_libtool"))
+ project->values("QMAKE_LFLAGS") += project->values("QMAKE_LFLAGS_SONAME");
+ } else {
+ project->values("QMAKE_LFLAGS") += project->values("QMAKE_LFLAGS_SHLIB");
+ if(!project->isEmpty("QMAKE_LFLAGS_COMPAT_VERSION")) {
+ if(project->isEmpty("COMPAT_VERSION"))
+ project->values("QMAKE_LFLAGS") += QString(project->first("QMAKE_LFLAGS_COMPAT_VERSION") +
+ project->first("VER_MAJ") + "." +
+ project->first("VER_MIN"));
+ else
+ project->values("QMAKE_LFLAGS") += QString(project->first("QMAKE_LFLAGS_COMPAT_VERSION") +
+ project->first("COMPATIBILITY_VERSION"));
+ }
+ if(!project->isEmpty("QMAKE_LFLAGS_VERSION")) {
+ project->values("QMAKE_LFLAGS") += QString(project->first("QMAKE_LFLAGS_VERSION") +
+ project->first("VER_MAJ") + "." +
+ project->first("VER_MIN") + "." +
+ project->first("VER_PAT"));
+ }
+ if(!project->isActiveConfig("compile_libtool"))
+ project->values("QMAKE_LFLAGS") += project->values("QMAKE_LFLAGS_SONAME");
+ }
+ }
+
+ if(!project->isEmpty("QMAKE_BUNDLE")) {
+ QString plist = fileFixify(project->first("QMAKE_INFO_PLIST"));
+ if(plist.isEmpty())
+ plist = specdir() + QDir::separator() + "Info.plist." + project->first("TEMPLATE");
+ if(exists(Option::fixPathToLocalOS(plist))) {
+ if(project->isEmpty("QMAKE_INFO_PLIST"))
+ project->values("QMAKE_INFO_PLIST").append(plist);
+ project->values("QMAKE_INFO_PLIST_OUT").append(project->first("DESTDIR") +
+ project->first("QMAKE_BUNDLE") +
+ "/Contents/Info.plist");
+ project->values("ALL_DEPS") += project->first("QMAKE_INFO_PLIST_OUT");
+ if(!project->isEmpty("ICON") && project->first("TEMPLATE") == "app")
+ project->values("ALL_DEPS") += project->first("DESTDIR") +
+ project->first("QMAKE_BUNDLE") +
+ "/Contents/Resources/" + project->first("ICON").section('/', -1);
+ if(!project->isEmpty("QMAKE_BUNDLE_DATA")) {
+ QString bundle_dir = project->first("DESTDIR") + project->first("QMAKE_BUNDLE") + "/";
+ QStringList &alldeps = project->values("ALL_DEPS");
+ const QStringList &bundle_data = project->values("QMAKE_BUNDLE_DATA");
+ for(int i = 0; i < bundle_data.count(); i++) {
+ const QStringList &files = project->values(bundle_data[i] + ".files");
+ QString path = bundle_dir;
+ if(!project->isEmpty(bundle_data[i] + ".version")) {
+ alldeps += Option::fixPathToLocalOS(path + Option::dir_sep +
+ project->first(bundle_data[i] + ".path"));
+ path += project->first(bundle_data[i] + ".version") + "/" +
+ project->first("QMAKE_FRAMEWORK_VERSION") + "/";
+ }
+ path += project->first(bundle_data[i] + ".path");
+ path = Option::fixPathToLocalOS(path);
+ for(int file = 0; file < files.count(); file++)
+ alldeps += path + Option::dir_sep + fileInfo(files[file]).fileName();
+ }
+ }
+ }
+ }
+}
+
+QString
+UnixMakefileGenerator::libtoolFileName(bool fixify)
+{
+ QString ret = var("TARGET");
+ int slsh = ret.lastIndexOf(Option::dir_sep);
+ if(slsh != -1)
+ ret = ret.right(ret.length() - slsh - 1);
+ int dot = ret.indexOf('.');
+ if(dot != -1)
+ ret = ret.left(dot);
+ ret += Option::libtool_ext;
+ if(!project->isEmpty("QMAKE_LIBTOOL_DESTDIR"))
+ ret.prepend(project->first("QMAKE_LIBTOOL_DESTDIR") + Option::dir_sep);
+ if(fixify) {
+ if(QDir::isRelativePath(ret) && !project->isEmpty("DESTDIR"))
+ ret.prepend(project->first("DESTDIR"));
+ ret = Option::fixPathToLocalOS(fileFixify(ret, qmake_getpwd(), Option::output_dir));
+ }
+ return ret;
+}
+
+void
+UnixMakefileGenerator::writeLibtoolFile()
+{
+ QString fname = libtoolFileName(), lname = fname;
+ mkdir(fileInfo(fname).path());
+ int slsh = lname.lastIndexOf(Option::dir_sep);
+ if(slsh != -1)
+ lname = lname.right(lname.length() - slsh - 1);
+ QFile ft(fname);
+ if(!ft.open(QIODevice::WriteOnly))
+ return;
+ project->values("ALL_DEPS").append(fileFixify(fname));
+
+ QTextStream t(&ft);
+ t << "# " << lname << " - a libtool library file\n";
+ t << "# Generated by qmake/libtool (" << qmake_version() << ") (Qt "
+ << QT_VERSION_STR << ") on: " << QDateTime::currentDateTime().toString();
+ t << "\n";
+
+ t << "# The name that we can dlopen(3).\n"
+ << "dlname='" << var(project->isActiveConfig("plugin") ? "TARGET" : "TARGET_x")
+ << "'\n\n";
+
+ t << "# Names of this library.\n";
+ t << "library_names='";
+ if(project->isActiveConfig("plugin")) {
+ t << var("TARGET");
+ } else {
+ if (project->isEmpty("QMAKE_HPUX_SHLIB"))
+ t << var("TARGET_x.y.z") << " ";
+ t << var("TARGET_x") << " " << var("TARGET_");
+ }
+ t << "'\n\n";
+
+ t << "# The name of the static archive.\n"
+ << "old_library='" << lname.left(lname.length()-Option::libtool_ext.length()) << ".a'\n\n";
+
+ t << "# Libraries that this one depends upon.\n";
+ QStringList libs;
+ if(!project->isEmpty("QMAKE_INTERNAL_PRL_LIBS"))
+ libs = project->values("QMAKE_INTERNAL_PRL_LIBS");
+ else
+ libs << "QMAKE_LIBS"; //obvious one
+ t << "dependency_libs='";
+ for(QStringList::ConstIterator it = libs.begin(); it != libs.end(); ++it)
+ t << project->values((*it)).join(" ") << " ";
+ t << "'\n\n";
+
+ t << "# Version information for " << lname << "\n";
+ int maj = project->first("VER_MAJ").toInt();
+ int min = project->first("VER_MIN").toInt();
+ int pat = project->first("VER_PAT").toInt();
+ t << "current=" << (10*maj + min) << "\n" // best I can think of
+ << "age=0\n"
+ << "revision=" << pat << "\n\n";
+
+ t << "# Is this an already installed library.\n"
+ "installed=yes\n\n"; // ###
+
+ t << "# Files to dlopen/dlpreopen.\n"
+ "dlopen=''\n"
+ "dlpreopen=''\n\n";
+
+ QString install_dir = project->first("QMAKE_LIBTOOL_LIBDIR");
+ if(install_dir.isEmpty())
+ install_dir = project->first("target.path");
+ if(install_dir.isEmpty())
+ install_dir = project->first("DESTDIR");
+ t << "# Directory that this library needs to be installed in:\n"
+ "libdir='" << Option::fixPathToTargetOS(install_dir, false) << "'\n";
+}
+
+QString
+UnixMakefileGenerator::pkgConfigFileName(bool fixify)
+{
+ QString ret = var("TARGET");
+ int slsh = ret.lastIndexOf(Option::dir_sep);
+ if(slsh != -1)
+ ret = ret.right(ret.length() - slsh - 1);
+ if(ret.startsWith("lib"))
+ ret = ret.mid(3);
+ int dot = ret.indexOf('.');
+ if(dot != -1)
+ ret = ret.left(dot);
+ ret += Option::pkgcfg_ext;
+ if(!project->isEmpty("QMAKE_PKGCONFIG_DESTDIR"))
+ ret.prepend(project->first("QMAKE_PKGCONFIG_DESTDIR") + Option::dir_sep);
+ if(fixify) {
+ if(QDir::isRelativePath(ret) && !project->isEmpty("DESTDIR"))
+ ret.prepend(project->first("DESTDIR"));
+ ret = Option::fixPathToLocalOS(fileFixify(ret, qmake_getpwd(), Option::output_dir));
+ }
+ return ret;
+}
+
+QString
+UnixMakefileGenerator::pkgConfigPrefix() const
+{
+ if(!project->isEmpty("QMAKE_PKGCONFIG_PREFIX"))
+ return project->first("QMAKE_PKGCONFIG_PREFIX");
+ return QLibraryInfo::location(QLibraryInfo::PrefixPath);
+}
+
+QString
+UnixMakefileGenerator::pkgConfigFixPath(QString path) const
+{
+ QString prefix = pkgConfigPrefix();
+ if(path.startsWith(prefix))
+ path = path.replace(prefix, "${prefix}");
+ return path;
+}
+
+void
+UnixMakefileGenerator::writePkgConfigFile()
+{
+ QString fname = pkgConfigFileName(), lname = fname;
+ mkdir(fileInfo(fname).path());
+ int slsh = lname.lastIndexOf(Option::dir_sep);
+ if(slsh != -1)
+ lname = lname.right(lname.length() - slsh - 1);
+ QFile ft(fname);
+ if(!ft.open(QIODevice::WriteOnly))
+ return;
+ project->values("ALL_DEPS").append(fileFixify(fname));
+ QTextStream t(&ft);
+
+ QString prefix = pkgConfigPrefix();
+ QString libDir = project->first("QMAKE_PKGCONFIG_LIBDIR");
+ if(libDir.isEmpty())
+ libDir = prefix + Option::dir_sep + "lib" + Option::dir_sep;
+ QString includeDir = project->first("QMAKE_PKGCONFIG_INCDIR");
+ if(includeDir.isEmpty())
+ includeDir = prefix + "/include";
+
+ t << "prefix=" << prefix << endl;
+ t << "exec_prefix=${prefix}\n"
+ << "libdir=" << pkgConfigFixPath(libDir) << "\n"
+ << "includedir=" << pkgConfigFixPath(includeDir) << endl;
+ // non-standard entry. Provides useful info normally only
+ // contained in the internal .qmake.cache file
+ t << varGlue("CONFIG", "qt_config=", " ", "") << endl;
+
+ //extra PKGCONFIG variables
+ const QStringList &pkgconfig_vars = project->values("QMAKE_PKGCONFIG_VARIABLES");
+ for(int i = 0; i < pkgconfig_vars.size(); ++i) {
+ QString var = project->first(pkgconfig_vars.at(i) + ".name"),
+ val = project->values(pkgconfig_vars.at(i) + ".value").join(" ");
+ if(var.isEmpty())
+ continue;
+ if(val.isEmpty()) {
+ const QStringList &var_vars = project->values(pkgconfig_vars.at(i) + ".variable");
+ for(int v = 0; v < var_vars.size(); ++v) {
+ const QStringList &vars = project->values(var_vars.at(v));
+ for(int var = 0; var < vars.size(); ++var) {
+ if(!val.isEmpty())
+ val += " ";
+ val += pkgConfigFixPath(vars.at(var));
+ }
+ }
+ }
+ t << var << "=" << val << endl;
+ }
+
+ t << endl;
+
+ QString name = project->first("QMAKE_PKGCONFIG_NAME");
+ if(name.isEmpty()) {
+ name = project->first("QMAKE_ORIG_TARGET").toLower();
+ name.replace(0, 1, name[0].toUpper());
+ }
+ t << "Name: " << name << endl;
+ QString desc = project->values("QMAKE_PKGCONFIG_DESCRIPTION").join(" ");
+ if(desc.isEmpty()) {
+ if(name.isEmpty()) {
+ desc = project->first("QMAKE_ORIG_TARGET").toLower();
+ desc.replace(0, 1, desc[0].toUpper());
+ } else {
+ desc = name;
+ }
+ if(project->first("TEMPLATE") == "lib") {
+ if(project->isActiveConfig("plugin"))
+ desc += " Plugin";
+ else
+ desc += " Library";
+ } else if(project->first("TEMPLATE") == "app") {
+ desc += " Application";
+ }
+ }
+ t << "Description: " << desc << endl;
+ t << "Version: " << project->first("VERSION") << endl;
+
+ // libs
+ QStringList libs;
+ if(!project->isEmpty("QMAKE_INTERNAL_PRL_LIBS")) {
+ libs = project->values("QMAKE_INTERNAL_PRL_LIBS");
+ } else {
+ libs << "QMAKE_LIBS"; //obvious one
+ }
+ libs << "QMAKE_LFLAGS_THREAD"; //not sure about this one, but what about things like -pthread?
+ t << "Libs: ";
+ QString pkgConfiglibDir;
+ QString pkgConfiglibName;
+ if (Option::target_mode == Option::TARG_MACX_MODE && project->isActiveConfig("lib_bundle")) {
+ pkgConfiglibDir = "-F${libdir}";
+ QString bundle;
+ if (!project->isEmpty("QMAKE_FRAMEWORK_BUNDLE_NAME"))
+ bundle = unescapeFilePath(project->first("QMAKE_FRAMEWORK_BUNDLE_NAME"));
+ else
+ bundle = unescapeFilePath(project->first("TARGET"));
+ int suffix = bundle.lastIndexOf(".framework");
+ if (suffix != -1)
+ bundle = bundle.left(suffix);
+ pkgConfiglibName = "-framework " + bundle + " ";
+ } else {
+ pkgConfiglibDir = "-L${libdir}";
+ pkgConfiglibName = "-l" + lname.left(lname.length()-Option::libtool_ext.length());
+ }
+ t << pkgConfiglibDir << " " << pkgConfiglibName << " " << endl;
+ t << "Libs.private: ";
+ for(QStringList::ConstIterator it = libs.begin(); it != libs.end(); ++it) {
+ t << project->values((*it)).join(" ") << " ";
+ }
+ t << endl;
+
+ // flags
+ // ### too many
+ t << "Cflags: "
+ // << var("QMAKE_CXXFLAGS") << " "
+ << varGlue("PRL_EXPORT_DEFINES","-D"," -D"," ")
+ << project->values("PRL_EXPORT_CXXFLAGS").join(" ")
+ << project->values("QMAKE_PKGCONFIG_CFLAGS").join(" ")
+ // << varGlue("DEFINES","-D"," -D"," ")
+ << " -I${includedir}" << endl;
+
+ // requires
+ const QString requires = project->values("QMAKE_PKGCONFIG_REQUIRES").join(" ");
+ if (!requires.isEmpty()) {
+ t << "Requires: " << requires << endl;
+ }
+
+ t << endl;
+}
+
+QT_END_NAMESPACE
diff --git a/qmake/generators/win32/borland_bmake.cpp b/qmake/generators/win32/borland_bmake.cpp
new file mode 100644
index 0000000..411c7ab
--- /dev/null
+++ b/qmake/generators/win32/borland_bmake.cpp
@@ -0,0 +1,177 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "borland_bmake.h"
+#include "option.h"
+#include <qdir.h>
+#include <qregexp.h>
+#include <time.h>
+
+QT_BEGIN_NAMESPACE
+
+BorlandMakefileGenerator::BorlandMakefileGenerator() : Win32MakefileGenerator(), init_flag(false)
+{
+
+}
+
+bool
+BorlandMakefileGenerator::writeMakefile(QTextStream &t)
+{
+ writeHeader(t);
+ if(!project->values("QMAKE_FAILED_REQUIREMENTS").isEmpty()) {
+ QStringList &qut = project->values("QMAKE_EXTRA_TARGETS");
+ for(QStringList::ConstIterator it = qut.begin(); it != qut.end(); ++it)
+ t << *it << " ";
+ t << "all first clean:" << "\n\t"
+ << "@echo \"Some of the required modules ("
+ << var("QMAKE_FAILED_REQUIREMENTS") << ") are not available.\"" << "\n\t"
+ << "@echo \"Skipped.\"" << endl << endl;
+ return true;
+ }
+
+ if(project->first("TEMPLATE") == "app" ||
+ project->first("TEMPLATE") == "lib") {
+ writeBorlandParts(t);
+ return MakefileGenerator::writeMakefile(t);
+ }
+ else if(project->first("TEMPLATE") == "subdirs") {
+ writeSubDirs(t);
+ return true;
+ }
+ return false;
+}
+
+void
+BorlandMakefileGenerator::writeBorlandParts(QTextStream &t)
+{
+ t << "!if !$d(BCB)" << endl;
+ t << "BCB = $(MAKEDIR)\\.." << endl;
+ t << "!endif" << endl << endl;
+
+ writeStandardParts(t);
+}
+
+void
+BorlandMakefileGenerator::init()
+{
+ if(init_flag)
+ return;
+ init_flag = true;
+
+ /* this should probably not be here, but I'm using it to wrap the .t files */
+ if (project->first("TEMPLATE") == "app") {
+ project->values("QMAKE_APP_FLAG").append("1");
+ } else if(project->first("TEMPLATE") == "lib"){
+ project->values("QMAKE_LIB_FLAG").append("1");
+ } else if(project->first("TEMPLATE") == "subdirs") {
+ MakefileGenerator::init();
+ if(project->isEmpty("QMAKE_COPY_FILE"))
+ project->values("QMAKE_COPY_FILE").append("$(COPY)");
+ if(project->isEmpty("QMAKE_COPY_DIR"))
+ project->values("QMAKE_COPY_DIR").append("xcopy /s /q /y /i");
+ if(project->isEmpty("QMAKE_INSTALL_FILE"))
+ project->values("QMAKE_INSTALL_FILE").append("$(COPY_FILE)");
+ if(project->isEmpty("QMAKE_INSTALL_PROGRAM"))
+ project->values("QMAKE_INSTALL_PROGRAM").append("$(COPY_FILE)");
+ if(project->isEmpty("QMAKE_INSTALL_DIR"))
+ project->values("QMAKE_INSTALL_DIR").append("$(COPY_DIR)");
+ if(project->values("MAKEFILE").isEmpty())
+ project->values("MAKEFILE").append("Makefile");
+ if(project->values("QMAKE_QMAKE").isEmpty())
+ project->values("QMAKE_QMAKE").append("qmake");
+ return;
+ }
+
+ processVars();
+
+ project->values("QMAKE_LIBS") += project->values("LIBS");
+
+ MakefileGenerator::init();
+
+ if (project->isActiveConfig("dll") || !project->values("QMAKE_APP_FLAG").isEmpty()) {
+ // bcc does not generate a .tds file for static libs
+ QString tdsPostfix;
+ if (!project->values("VERSION").isEmpty())
+ tdsPostfix = project->first("TARGET_VERSION_EXT");
+ tdsPostfix += ".tds";
+ project->values("QMAKE_CLEAN").append(project->first("DESTDIR") + project->first("TARGET") + tdsPostfix);
+ }
+}
+
+void BorlandMakefileGenerator::writeBuildRulesPart(QTextStream &t)
+{
+ t << "first: all" << endl;
+ t << "all: " << fileFixify(Option::output.fileName()) << " " << varGlue("ALL_DEPS"," "," "," ") << " $(DESTDIR_TARGET)" << endl << endl;
+ t << "$(DESTDIR_TARGET): " << var("PRE_TARGETDEPS") << " $(OBJECTS) " << var("POST_TARGETDEPS");
+ if(!project->isEmpty("QMAKE_PRE_LINK"))
+ t << "\n\t" <<var("QMAKE_PRE_LINK");
+ if(project->isActiveConfig("staticlib")) {
+ t << "\n\t-$(DEL_FILE) $(DESTDIR_TARGET)"
+ << "\n\t" << "$(LIB) $(DESTDIR_TARGET) @&&|" << " \n+"
+ << project->values("OBJECTS").join(" \\\n+") << " \\\n+"
+ << project->values("OBJMOC").join(" \\\n+");
+ } else {
+ t << "\n\t" << "$(LINK) @&&|" << "\n\t"
+ << "$(LFLAGS) $(OBJECTS) $(OBJMOC),$(DESTDIR_TARGET),,$(LIBS),$(DEF_FILE),$(RES_FILE)";
+ }
+ t << endl << "|";
+ if(!project->isEmpty("QMAKE_POST_LINK"))
+ t << "\n\t" <<var("QMAKE_POST_LINK");
+ t << endl;
+}
+
+void BorlandMakefileGenerator::writeCleanParts(QTextStream &t)
+{
+ t << "clean: "
+ << varGlue("OBJECTS","\n\t-$(DEL_FILE) ","\n\t-$(DEL_FILE) ","")
+ << varGlue("QMAKE_CLEAN","\n\t-$(DEL_FILE) ","\n\t-$(DEL_FILE) ","\n")
+ << varGlue("CLEAN_FILES","\n\t-$(DEL_FILE) ","\n\t-$(DEL_FILE) ","\n");
+
+ if(!project->isEmpty("IMAGES"))
+ t << varGlue("QMAKE_IMAGE_COLLECTION", "\n\t-$(DEL_FILE) ", "\n\t-$(DEL_FILE) ", "");
+ t << endl;
+
+ t << "distclean: clean"
+ << "\n\t-$(DEL_FILE) $(DESTDIR_TARGET)"
+ << endl << endl;
+}
+
+QT_END_NAMESPACE
diff --git a/qmake/generators/win32/borland_bmake.h b/qmake/generators/win32/borland_bmake.h
new file mode 100644
index 0000000..46c7d0a
--- /dev/null
+++ b/qmake/generators/win32/borland_bmake.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef BORLAND_BMAKE_H
+#define BORLAND_BMAKE_H
+
+#include "winmakefile.h"
+
+QT_BEGIN_NAMESPACE
+
+class BorlandMakefileGenerator : public Win32MakefileGenerator
+{
+ bool init_flag;
+ void writeBorlandParts(QTextStream &);
+ void writeBuildRulesPart(QTextStream &t);
+ void writeCleanParts(QTextStream &t);
+ bool writeMakefile(QTextStream &);
+ void init();
+
+public:
+ BorlandMakefileGenerator();
+ ~BorlandMakefileGenerator();
+};
+
+inline BorlandMakefileGenerator::~BorlandMakefileGenerator()
+{ }
+
+QT_END_NAMESPACE
+
+#endif // BORLAND_BMAKE_H
diff --git a/qmake/generators/win32/mingw_make.cpp b/qmake/generators/win32/mingw_make.cpp
new file mode 100644
index 0000000..7473b10
--- /dev/null
+++ b/qmake/generators/win32/mingw_make.cpp
@@ -0,0 +1,460 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "mingw_make.h"
+#include "option.h"
+#include "meta.h"
+#include <qregexp.h>
+#include <qdir.h>
+#include <stdlib.h>
+#include <time.h>
+
+QT_BEGIN_NAMESPACE
+
+MingwMakefileGenerator::MingwMakefileGenerator() : Win32MakefileGenerator(), init_flag(false)
+{
+ if (Option::shellPath.isEmpty())
+ quote = "\"";
+ else
+ quote = "'";
+}
+
+bool MingwMakefileGenerator::isWindowsShell() const
+{
+#ifdef Q_OS_WIN
+ return Option::shellPath.isEmpty();
+#else
+ return Win32MakefileGenerator::isWindowsShell();
+#endif
+}
+
+QString MingwMakefileGenerator::escapeDependencyPath(const QString &path) const
+{
+ QString ret = path;
+ ret.remove('\"');
+ ret.replace('\\', "/");
+ ret.replace(' ', "\\ ");
+ return ret;
+}
+
+QString MingwMakefileGenerator::getLibTarget()
+{
+ return QString("lib" + project->first("TARGET") + project->first("TARGET_VERSION_EXT") + ".a");
+}
+
+bool MingwMakefileGenerator::findLibraries()
+{
+ QStringList &l = project->values("QMAKE_LIBS");
+
+ QList<QMakeLocalFileName> dirs;
+ {
+ QStringList &libpaths = project->values("QMAKE_LIBDIR");
+ for(QStringList::Iterator libpathit = libpaths.begin();
+ libpathit != libpaths.end(); ++libpathit)
+ dirs.append(QMakeLocalFileName((*libpathit)));
+ }
+
+ QStringList::Iterator it = l.begin();
+ while (it != l.end()) {
+ if ((*it).startsWith("-l")) {
+ QString steam = (*it).mid(2), out;
+ QString suffix;
+ if (!project->isEmpty("QMAKE_" + steam.toUpper() + "_SUFFIX"))
+ suffix = project->first("QMAKE_" + steam.toUpper() + "_SUFFIX");
+ for (QList<QMakeLocalFileName>::Iterator dir_it = dirs.begin(); dir_it != dirs.end(); ++dir_it) {
+ QString extension;
+ int ver = findHighestVersion((*dir_it).local(), steam, "dll.a|a");
+ if (ver != -1)
+ extension += QString::number(ver);
+ extension += suffix;
+ if(QMakeMetaInfo::libExists((*dir_it).local() + Option::dir_sep + steam) ||
+ exists((*dir_it).local() + Option::dir_sep + steam + extension + ".a") ||
+ exists((*dir_it).local() + Option::dir_sep + steam + extension + ".dll.a")) {
+ out = (*it) + extension;
+ break;
+ }
+ }
+ if (!out.isEmpty()) // We assume if it never finds it that its correct
+ (*it) = out;
+ } else if((*it).startsWith("-L")) {
+ dirs.append(QMakeLocalFileName((*it).mid(2)));
+ }
+
+ ++it;
+ }
+ return true;
+}
+
+bool MingwMakefileGenerator::writeMakefile(QTextStream &t)
+{
+ writeHeader(t);
+ if(!project->values("QMAKE_FAILED_REQUIREMENTS").isEmpty()) {
+ t << "all clean:" << "\n\t"
+ << "@echo \"Some of the required modules ("
+ << var("QMAKE_FAILED_REQUIREMENTS") << ") are not available.\"" << "\n\t"
+ << "@echo \"Skipped.\"" << endl << endl;
+ writeMakeQmake(t);
+ return true;
+ }
+
+ if(project->first("TEMPLATE") == "app" ||
+ project->first("TEMPLATE") == "lib") {
+ if(Option::mkfile::do_stub_makefile) {
+ t << "QMAKE = " << (project->isEmpty("QMAKE_QMAKE") ? QString("qmake") : var("QMAKE_QMAKE")) << endl;
+ QStringList &qut = project->values("QMAKE_EXTRA_TARGETS");
+ for(QStringList::ConstIterator it = qut.begin(); it != qut.end(); ++it)
+ t << *it << " ";
+ t << "first all clean install distclean uninstall: qmake" << endl
+ << "qmake_all:" << endl;
+ writeMakeQmake(t);
+ if(project->isEmpty("QMAKE_NOFORCE"))
+ t << "FORCE:" << endl << endl;
+ return true;
+ }
+ writeMingwParts(t);
+ return MakefileGenerator::writeMakefile(t);
+ }
+ else if(project->first("TEMPLATE") == "subdirs") {
+ writeSubDirs(t);
+ return true;
+ }
+ return false;
+ }
+
+void createLdObjectScriptFile(const QString &fileName, const QStringList &objList)
+{
+ QString filePath = Option::output_dir + QDir::separator() + fileName;
+ QFile file(filePath);
+ if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
+ QTextStream t(&file);
+ t << "INPUT(" << endl;
+ for (QStringList::ConstIterator it = objList.constBegin(); it != objList.constEnd(); ++it) {
+ if (QDir::isRelativePath(*it))
+ t << "./" << *it << endl;
+ else
+ t << *it << endl;
+ }
+ t << ");" << endl;
+ t.flush();
+ file.close();
+ }
+}
+
+void createArObjectScriptFile(const QString &fileName, const QString &target, const QStringList &objList)
+{
+ QString filePath = Option::output_dir + QDir::separator() + fileName;
+ QFile file(filePath);
+ if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
+ QTextStream t(&file);
+ t << "CREATE " << target << endl;
+ for (QStringList::ConstIterator it = objList.constBegin(); it != objList.constEnd(); ++it) {
+ if (QDir::isRelativePath(*it))
+ t << "ADDMOD " << *it << endl;
+ else
+ t << *it << endl;
+ }
+ t << "SAVE" << endl;
+ t.flush();
+ file.close();
+ }
+}
+
+void MingwMakefileGenerator::writeMingwParts(QTextStream &t)
+{
+ writeStandardParts(t);
+
+ if (!preCompHeaderOut.isEmpty()) {
+ QString header = project->first("PRECOMPILED_HEADER");
+ QString cHeader = preCompHeaderOut + Option::dir_sep + "c";
+ t << escapeDependencyPath(cHeader) << ": " << escapeDependencyPath(header) << " "
+ << escapeDependencyPaths(findDependencies(header)).join(" \\\n\t\t")
+ << "\n\t" << mkdir_p_asstring(preCompHeaderOut)
+ << "\n\t" << "$(CC) -x c-header -c $(CFLAGS) $(INCPATH) -o " << cHeader << " " << header
+ << endl << endl;
+ QString cppHeader = preCompHeaderOut + Option::dir_sep + "c++";
+ t << escapeDependencyPath(cppHeader) << ": " << escapeDependencyPath(header) << " "
+ << escapeDependencyPaths(findDependencies(header)).join(" \\\n\t\t")
+ << "\n\t" << mkdir_p_asstring(preCompHeaderOut)
+ << "\n\t" << "$(CXX) -x c++-header -c $(CXXFLAGS) $(INCPATH) -o " << cppHeader << " " << header
+ << endl << endl;
+ }
+}
+
+void MingwMakefileGenerator::init()
+{
+ if(init_flag)
+ return;
+ init_flag = true;
+
+ /* this should probably not be here, but I'm using it to wrap the .t files */
+ if(project->first("TEMPLATE") == "app")
+ project->values("QMAKE_APP_FLAG").append("1");
+ else if(project->first("TEMPLATE") == "lib")
+ project->values("QMAKE_LIB_FLAG").append("1");
+ else if(project->first("TEMPLATE") == "subdirs") {
+ MakefileGenerator::init();
+ if(project->isEmpty("QMAKE_COPY_FILE"))
+ project->values("QMAKE_COPY_FILE").append("$(COPY)");
+ if(project->isEmpty("QMAKE_COPY_DIR"))
+ project->values("QMAKE_COPY_DIR").append("xcopy /s /q /y /i");
+ if(project->isEmpty("QMAKE_INSTALL_FILE"))
+ project->values("QMAKE_INSTALL_FILE").append("$(COPY_FILE)");
+ if(project->isEmpty("QMAKE_INSTALL_PROGRAM"))
+ project->values("QMAKE_INSTALL_PROGRAM").append("$(COPY_FILE)");
+ if(project->isEmpty("QMAKE_INSTALL_DIR"))
+ project->values("QMAKE_INSTALL_DIR").append("$(COPY_DIR)");
+ if(project->values("MAKEFILE").isEmpty())
+ project->values("MAKEFILE").append("Makefile");
+ if(project->values("QMAKE_QMAKE").isEmpty())
+ project->values("QMAKE_QMAKE").append("qmake");
+ return;
+ }
+
+ project->values("TARGET_PRL").append(project->first("TARGET"));
+
+ processVars();
+
+ if (!project->values("RES_FILE").isEmpty()) {
+ project->values("QMAKE_LIBS") += escapeFilePaths(project->values("RES_FILE"));
+ }
+
+ // LIBS defined in Profile comes first for gcc
+ project->values("QMAKE_LIBS") += escapeFilePaths(project->values("LIBS"));
+
+ QString targetfilename = project->values("TARGET").first();
+ QStringList &configs = project->values("CONFIG");
+
+ if(project->isActiveConfig("qt_dll"))
+ if(configs.indexOf("qt") == -1)
+ configs.append("qt");
+
+ if(project->isActiveConfig("dll")) {
+ QString destDir = "";
+ if(!project->first("DESTDIR").isEmpty())
+ destDir = Option::fixPathToTargetOS(project->first("DESTDIR") + Option::dir_sep, false, false);
+ project->values("MINGW_IMPORT_LIB").prepend(destDir + "lib" + project->first("TARGET")
+ + project->first("TARGET_VERSION_EXT") + ".a");
+ project->values("QMAKE_LFLAGS").append(QString("-Wl,--out-implib,") + project->first("MINGW_IMPORT_LIB"));
+ }
+
+ if(!project->values("DEF_FILE").isEmpty())
+ project->values("QMAKE_LFLAGS").append(QString("-Wl,") + project->first("DEF_FILE"));
+
+ MakefileGenerator::init();
+
+ // precomp
+ if (!project->first("PRECOMPILED_HEADER").isEmpty()
+ && project->isActiveConfig("precompile_header")) {
+ QString preCompHeader = var("PRECOMPILED_DIR")
+ + QFileInfo(project->first("PRECOMPILED_HEADER")).fileName();
+ preCompHeaderOut = preCompHeader + ".gch";
+ project->values("QMAKE_CLEAN").append(preCompHeaderOut + Option::dir_sep + "c");
+ project->values("QMAKE_CLEAN").append(preCompHeaderOut + Option::dir_sep + "c++");
+
+ project->values("QMAKE_RUN_CC").clear();
+ project->values("QMAKE_RUN_CC").append("$(CC) -c -include " + preCompHeader +
+ " $(CFLAGS) $(INCPATH) -o $obj $src");
+ project->values("QMAKE_RUN_CC_IMP").clear();
+ project->values("QMAKE_RUN_CC_IMP").append("$(CC) -c -include " + preCompHeader +
+ " $(CFLAGS) $(INCPATH) -o $@ $<");
+ project->values("QMAKE_RUN_CXX").clear();
+ project->values("QMAKE_RUN_CXX").append("$(CXX) -c -include " + preCompHeader +
+ " $(CXXFLAGS) $(INCPATH) -o $obj $src");
+ project->values("QMAKE_RUN_CXX_IMP").clear();
+ project->values("QMAKE_RUN_CXX_IMP").append("$(CXX) -c -include " + preCompHeader +
+ " $(CXXFLAGS) $(INCPATH) -o $@ $<");
+ }
+
+ if(project->isActiveConfig("dll")) {
+ project->values("QMAKE_CLEAN").append(project->first("MINGW_IMPORT_LIB"));
+ }
+}
+
+void MingwMakefileGenerator::fixTargetExt()
+{
+ if (project->isActiveConfig("staticlib") && project->first("TEMPLATE") == "lib") {
+ project->values("TARGET_EXT").append(".a");
+ project->values("QMAKE_LFLAGS").append("-static");
+ project->values("TARGET").first() = "lib" + project->first("TARGET");
+ } else {
+ Win32MakefileGenerator::fixTargetExt();
+ }
+}
+
+void MingwMakefileGenerator::writeIncPart(QTextStream &t)
+{
+ t << "INCPATH = ";
+
+ QStringList &incs = project->values("INCLUDEPATH");
+ for(QStringList::Iterator incit = incs.begin(); incit != incs.end(); ++incit) {
+ QString inc = (*incit);
+ inc.replace(QRegExp("\\\\$"), "");
+ inc.replace(QRegExp("\""), "");
+ t << "-I" << quote << inc << quote << " ";
+ }
+ t << "-I" << quote << specdir() << quote
+ << endl;
+}
+
+void MingwMakefileGenerator::writeLibsPart(QTextStream &t)
+{
+ if(project->isActiveConfig("staticlib") && project->first("TEMPLATE") == "lib") {
+ t << "LIB = " << var("QMAKE_LIB") << endl;
+ } else {
+ t << "LINK = " << var("QMAKE_LINK") << endl;
+ t << "LFLAGS = " << var("QMAKE_LFLAGS") << endl;
+ t << "LIBS = ";
+ if(!project->values("QMAKE_LIBDIR").isEmpty())
+ writeLibDirPart(t);
+ t << var("QMAKE_LIBS").replace(QRegExp("(\\slib|^lib)")," -l") << endl;
+ }
+}
+
+void MingwMakefileGenerator::writeLibDirPart(QTextStream &t)
+{
+ QStringList libDirs = project->values("QMAKE_LIBDIR");
+ for (int i = 0; i < libDirs.size(); ++i)
+ libDirs[i].remove("\"");
+ t << valGlue(libDirs,"-L"+quote,quote+" -L" +quote,quote) << " ";
+}
+
+void MingwMakefileGenerator::writeObjectsPart(QTextStream &t)
+{
+ if (project->values("OBJECTS").count() < var("QMAKE_LINK_OBJECT_MAX").toInt()) {
+ objectsLinkLine = "$(OBJECTS)";
+ } else if (project->isActiveConfig("staticlib") && project->first("TEMPLATE") == "lib") {
+ QString ar_script_file = var("QMAKE_LINK_OBJECT_SCRIPT") + "." + var("TARGET");
+ if (!var("BUILD_NAME").isEmpty()) {
+ ar_script_file += "." + var("BUILD_NAME");
+ }
+ createArObjectScriptFile(ar_script_file, var("DEST_TARGET"), project->values("OBJECTS"));
+ objectsLinkLine = "ar -M < " + ar_script_file;
+ } else {
+ QString ld_script_file = var("QMAKE_LINK_OBJECT_SCRIPT") + "." + var("TARGET");
+ if (!var("BUILD_NAME").isEmpty()) {
+ ld_script_file += "." + var("BUILD_NAME");
+ }
+ createLdObjectScriptFile(ld_script_file, project->values("OBJECTS"));
+ objectsLinkLine = ld_script_file;
+ }
+ Win32MakefileGenerator::writeObjectsPart(t);
+}
+
+void MingwMakefileGenerator::writeBuildRulesPart(QTextStream &t)
+{
+ t << "first: all" << endl;
+ t << "all: " << escapeDependencyPath(fileFixify(Option::output.fileName())) << " " << valGlue(escapeDependencyPaths(project->values("ALL_DEPS"))," "," "," ") << " $(DESTDIR_TARGET)" << endl << endl;
+ t << "$(DESTDIR_TARGET): " << var("PRE_TARGETDEPS") << " $(OBJECTS) " << var("POST_TARGETDEPS");
+ if(!project->isEmpty("QMAKE_PRE_LINK"))
+ t << "\n\t" <<var("QMAKE_PRE_LINK");
+ if(project->isActiveConfig("staticlib") && project->first("TEMPLATE") == "lib") {
+ if (project->values("OBJECTS").count() < var("QMAKE_LINK_OBJECT_MAX").toInt()) {
+ t << "\n\t" << "$(LIB) $(DESTDIR_TARGET) " << objectsLinkLine << " " ;
+ } else {
+ t << "\n\t" << objectsLinkLine << " " ;
+ }
+ } else {
+ t << "\n\t" << "$(LINK) $(LFLAGS) -o $(DESTDIR_TARGET) " << objectsLinkLine << " " << " $(LIBS)";
+ }
+ if(!project->isEmpty("QMAKE_POST_LINK"))
+ t << "\n\t" <<var("QMAKE_POST_LINK");
+ t << endl;
+}
+
+void MingwMakefileGenerator::writeRcFilePart(QTextStream &t)
+{
+ const QString rc_file = fileFixify(project->first("RC_FILE"));
+
+ QString incPathStr = fileInfo(rc_file).path();
+ if (incPathStr != "." && QDir::isRelativePath(incPathStr))
+ incPathStr.prepend("./");
+
+ if (!rc_file.isEmpty()) {
+ t << escapeDependencyPath(var("RES_FILE")) << ": " << rc_file << "\n\t"
+ << var("QMAKE_RC") << " -i " << rc_file << " -o " << var("RES_FILE")
+ << " --include-dir=" << incPathStr << endl << endl;
+ }
+}
+
+void MingwMakefileGenerator::processPrlVariable(const QString &var, const QStringList &l)
+{
+ if (var == "QMAKE_PRL_LIBS") {
+ QString where = "QMAKE_LIBS";
+ if (!project->isEmpty("QMAKE_INTERNAL_PRL_LIBS"))
+ where = project->first("QMAKE_INTERNAL_PRL_LIBS");
+ QStringList &out = project->values(where);
+ for (QStringList::ConstIterator it = l.begin(); it != l.end(); ++it) {
+ out.removeAll((*it));
+ out.append((*it));
+ }
+ } else {
+ Win32MakefileGenerator::processPrlVariable(var, l);
+ }
+}
+
+QStringList &MingwMakefileGenerator::findDependencies(const QString &file)
+{
+ QStringList &aList = MakefileGenerator::findDependencies(file);
+ // Note: The QMAKE_IMAGE_COLLECTION file have all images
+ // as dependency, so don't add precompiled header then
+ if (file == project->first("QMAKE_IMAGE_COLLECTION")
+ || preCompHeaderOut.isEmpty())
+ return aList;
+ for (QStringList::Iterator it = Option::c_ext.begin(); it != Option::c_ext.end(); ++it) {
+ if (file.endsWith(*it)) {
+ QString cHeader = preCompHeaderOut + Option::dir_sep + "c";
+ if (!aList.contains(cHeader))
+ aList += cHeader;
+ break;
+ }
+ }
+ for (QStringList::Iterator it = Option::cpp_ext.begin(); it != Option::cpp_ext.end(); ++it) {
+ if (file.endsWith(*it)) {
+ QString cppHeader = preCompHeaderOut + Option::dir_sep + "c++";
+ if (!aList.contains(cppHeader))
+ aList += cppHeader;
+ break;
+ }
+ }
+ return aList;
+}
+
+QT_END_NAMESPACE
diff --git a/qmake/generators/win32/mingw_make.h b/qmake/generators/win32/mingw_make.h
new file mode 100644
index 0000000..1c394b2
--- /dev/null
+++ b/qmake/generators/win32/mingw_make.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef MINGW_MAKE_H
+#define MINGW_MAKE_H
+
+#include "winmakefile.h"
+
+QT_BEGIN_NAMESPACE
+
+class MingwMakefileGenerator : public Win32MakefileGenerator
+{
+public:
+ MingwMakefileGenerator();
+ ~MingwMakefileGenerator();
+protected:
+ QString escapeDependencyPath(const QString &path) const;
+ QString getLibTarget();
+private:
+ bool isWindowsShell() const;
+ void writeMingwParts(QTextStream &);
+ void writeIncPart(QTextStream &t);
+ void writeLibsPart(QTextStream &t);
+ void writeLibDirPart(QTextStream &t);
+ bool writeMakefile(QTextStream &);
+ void writeObjectsPart(QTextStream &t);
+ void writeBuildRulesPart(QTextStream &t);
+ void writeRcFilePart(QTextStream &t);
+ void init();
+ void processPrlVariable(const QString &var, const QStringList &l);
+
+ QStringList &findDependencies(const QString &file);
+
+ QString preCompHeaderOut;
+
+ virtual bool findLibraries();
+ void fixTargetExt();
+
+ bool init_flag;
+ QString objectsLinkLine;
+ QString quote;
+};
+
+inline MingwMakefileGenerator::~MingwMakefileGenerator()
+{ }
+
+QT_END_NAMESPACE
+
+#endif // MINGW_MAKE_H
diff --git a/qmake/generators/win32/msvc_dsp.cpp b/qmake/generators/win32/msvc_dsp.cpp
new file mode 100644
index 0000000..17a5154
--- /dev/null
+++ b/qmake/generators/win32/msvc_dsp.cpp
@@ -0,0 +1,1207 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "msvc_dsp.h"
+#include "option.h"
+
+#include <qdir.h>
+#include <qset.h>
+
+#include <stdlib.h>
+
+QT_BEGIN_NAMESPACE
+
+DspMakefileGenerator::DspMakefileGenerator() : Win32MakefileGenerator(), init_flag(false)
+{
+}
+
+bool DspMakefileGenerator::writeMakefile(QTextStream &t)
+{
+ if(!project->values("QMAKE_FAILED_REQUIREMENTS").isEmpty()) {
+ /* for now just dump, I need to generated an empty dsp or something.. */
+ fprintf(stderr, "Project file not generated because all requirements not met:\n\t%s\n",
+ var("QMAKE_FAILED_REQUIREMENTS").toLatin1().constData());
+ return true;
+ }
+
+ // Generate workspace file
+ if(project->first("TEMPLATE") == "vcsubdirs") {
+ if (!project->isActiveConfig("build_pass")) {
+ debug_msg(1, "Generator: MSVC: Writing workspave file");
+ writeSubDirs(t);
+ } else {
+ debug_msg(1, "Generator: MSVC: Not writing workspace file for build_pass configs");
+ }
+ return true;
+ } else if (project->first("TEMPLATE") == "vcapp" || project->first("TEMPLATE") == "vclib") {
+ if(!project->isActiveConfig("build_pass"))
+ return writeDspParts(t);
+ return true;
+ }
+ return project->isActiveConfig("build_pass");
+}
+
+bool DspMakefileGenerator::hasBuiltinCompiler(const QString &filename) const
+{
+ for (int i = 0; i < Option::cpp_ext.count(); ++i)
+ if (filename.endsWith(Option::cpp_ext.at(i)))
+ return true;
+ for (int i = 0; i < Option::c_ext.count(); ++i)
+ if (filename.endsWith(Option::c_ext.at(i)))
+ return true;
+ return false;
+}
+
+QString DspMakefileGenerator::replaceExtraCompilerVariables(const QString &var, const QStringList &in, const QStringList &out)
+{
+ QString ret = MakefileGenerator::replaceExtraCompilerVariables(var, in, out);
+ ret.replace("$(DEFINES)", varGlue("PRL_EXPORT_DEFINES"," -D"," -D","") +
+ varGlue("DEFINES"," -D"," -D",""));
+
+ QString incpath = this->var("MSVCDSP_INCPATH");
+ incpath.replace("/I", "-I");
+ ret.replace("$(INCPATH)", incpath);
+ return ret;
+}
+
+
+// if config is part of a multibuild thenthe gule (this) has the correct MSVCDSP_PROJECT
+QString DspMakefileGenerator::configName(DspMakefileGenerator * config)
+{
+ return var("MSVCDSP_PROJECT") + config->var("MSVCDSP_CONFIG_NAME");
+}
+
+bool DspMakefileGenerator::writeDspHeader(QTextStream &t)
+{
+ DspMakefileGenerator * config = this;
+ if (mergedProjects.count())
+ config = mergedProjects.at(0);
+
+ t << "# Microsoft Developer Studio Project File - Name=\"" << var("MSVCDSP_PROJECT") << "\" - Package Owner=<4>" << endl;
+ t << "# Microsoft Developer Studio Generated Build File, Format Version 6.00" << endl;
+ t << "# ** DO NOT EDIT **" << endl;
+ t << endl;
+ t << "# TARGTYPE \"Win32 (x86) " << var("MSVCDSP_TARGETTYPE") << "\" " << var("MSVCDSP_DSPTYPE") << endl;
+ t << endl;
+ t << "CFG=\"" << configName(config) << "\"" << endl;
+ t << "!MESSAGE This is not a valid makefile. To build this project using NMAKE," << endl;
+ t << "!MESSAGE use the Export Makefile command and run" << endl;
+ t << "!MESSAGE " << endl;
+ t << "!MESSAGE NMAKE /f " << escapeFilePath(var("TARGET")) << ".mak." << endl;
+ t << "!MESSAGE " << endl;
+ t << "!MESSAGE You can specify a configuration when running NMAKE" << endl;
+ t << "!MESSAGE by defining the macro CFG on the command line. For example:" << endl;
+ t << "!MESSAGE " << endl;
+ t << "!MESSAGE NMAKE /f " << escapeFilePath(var("TARGET")) << ".mak CFG=\"" << configName(config) << "\"" << endl;
+ t << "!MESSAGE " << endl;
+ t << "!MESSAGE Possible choices for configuration are:" << endl;
+ t << "!MESSAGE " << endl;
+ if (mergedProjects.count()) {
+ for (int i = 0; i < mergedProjects.count(); ++i) {
+ DspMakefileGenerator * config = mergedProjects.at(i);
+ t << "!MESSAGE \"" << configName(config) << "\" (based on \"Win32 (x86) " << config->var("MSVCDSP_TARGETTYPE") << "\")" << endl;
+ }
+ } else {
+ t << "!MESSAGE \"" << configName(config) << "\" (based on \"Win32 (x86) " << config->var("MSVCDSP_TARGETTYPE") << "\")" << endl;
+ }
+ t << "!MESSAGE " << endl;
+ t << endl;
+ t << "# Begin Project" << endl;
+ t << "# PROP AllowPerConfigDependencies 0" << endl;
+ t << "# PROP Scc_ProjName \"\"" << endl;
+ t << "# PROP Scc_LocalPath \"\"" << endl;
+ t << "CPP=" << config->var("QMAKE_CC") << endl;
+ t << "MTL=" << config->var("QMAKE_IDL") << endl;
+ t << "RSC=" << config->var("QMAKE_RC") << endl;
+ t << "BSC32=bscmake.exe" << endl;
+
+ return true;
+}
+
+
+bool DspMakefileGenerator::writeDspParts(QTextStream &t)
+{
+ //bool staticLibTarget = var("MSVCDSP_DSPTYPE") == "0x0104";
+
+ writeDspHeader(t);
+ writeDspConfig(t, this);
+ t << endl;
+ t << "# Begin Target" << endl;
+ t << endl;
+ t << "# Name \"" << configName(this) << "\"" << endl;
+ t << endl;
+
+
+ QStringList listNames = QString("SOURCES|DEF_FILE").split("|");
+ QStringList allListNames = listNames;
+ writeFileGroup(t, listNames, "Source Files", "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat");
+ listNames = QStringList("HEADERS");
+ allListNames += listNames;
+ writeFileGroup(t, QStringList("HEADERS"), "Header Files", "h;hpp;hxx;hm;inl");
+ listNames = QString("FORMS|INTERFACES|FORMS3").split("|");
+ allListNames += listNames;
+ writeFileGroup(t, listNames, "Form Files", "ui");
+ listNames = QStringList("IMAGES");
+ allListNames += listNames;
+ writeFileGroup(t, QStringList("IMAGES"), "Image Files", "");
+ listNames = QString("RC_FILE|RESOURCES").split("|");
+ allListNames += listNames;
+ writeFileGroup(t, listNames, "Resources", "rc;qrc");
+ listNames = QStringList("TRANSLATIONS");
+ allListNames += listNames;
+ writeFileGroup(t, listNames, "Translations", "ts;xlf");
+ listNames = QStringList("LEXSOURCES");
+ allListNames += listNames;
+ writeFileGroup(t, listNames, "Lexables", "l");
+ listNames = QStringList("YACCSOURCES");
+ allListNames += listNames;
+ writeFileGroup(t, listNames, "Yaccables", "y");
+ listNames = QStringList("TYPELIBS");
+ allListNames += listNames;
+ writeFileGroup(t, listNames, "Type Libraries", "tlb;olb");
+
+ if (!project->isEmpty("QMAKE_EXTRA_COMPILERS")) {
+ const QStringList &quc = project->values("QMAKE_EXTRA_COMPILERS");
+ for (QStringList::ConstIterator it = quc.begin(); it != quc.end(); ++it) {
+ const QStringList &inputs = project->values((*it)+".input");
+ for (QStringList::ConstIterator input = inputs.begin(); input != inputs.end(); ++input) {
+ if (!allListNames.contains((*input)) && *input != "UIC3_HEADERS")
+ writeFileGroup(t, QStringList((*input)), (*input) + " Files", "");
+ }
+ }
+ }
+
+ project->values("SWAPPED_BUILD_STEPS") = swappedBuildSteps.keys();
+
+ writeFileGroup(t, QString("GENERATED_SOURCES|GENERATED_FILES|SWAPPED_BUILD_STEPS").split("|"), "Generated", "");
+
+ t << "# End Target" << endl;
+ t << "# End Project" << endl;
+ return true;
+}
+
+void
+DspMakefileGenerator::init()
+{
+ if(init_flag)
+ return;
+ QStringList::Iterator it;
+ init_flag = true;
+
+ platform = "Win32";
+ if(!project->values("QMAKE_PLATFORM").isEmpty())
+ platform = varGlue("QMAKE_PLATFORM", "", " ", "");
+
+ // this should probably not be here, but I'm using it to wrap the .t files
+ if(project->first("TEMPLATE") == "vcapp")
+ project->values("QMAKE_APP_FLAG").append("1");
+ else if(project->first("TEMPLATE") == "vclib")
+ project->values("QMAKE_LIB_FLAG").append("1");
+
+ if(project->values("QMAKESPEC").isEmpty())
+ project->values("QMAKESPEC").append(qgetenv("QMAKESPEC"));
+
+ project->values("QMAKE_LIBS") += escapeFilePaths(project->values("LIBS"));
+ processVars();
+
+ if(!project->values("VERSION").isEmpty()) {
+ QString version = project->values("VERSION").first();
+ int firstDot = version.indexOf(".");
+ QString major = version.left(firstDot);
+ QString minor = version.right(version.length() - firstDot - 1);
+ minor.replace(".", "");
+ project->values("MSVCDSP_LFLAGS").append("/VERSION:" + major + "." + minor);
+ }
+
+ QString msvcdsp_project;
+ if(!project->isEmpty("TARGET")) {
+ project->values("TARGET") = unescapeFilePaths(project->values("TARGET"));
+ msvcdsp_project = project->first("TARGET");
+ }
+
+ MakefileGenerator::init();
+
+ if(msvcdsp_project.isEmpty())
+ msvcdsp_project = Option::output.fileName();
+
+ msvcdsp_project = msvcdsp_project.right(msvcdsp_project.length() - msvcdsp_project.lastIndexOf("\\") - 1);
+ int dotFind = msvcdsp_project.lastIndexOf(".");
+ if(dotFind != -1)
+ msvcdsp_project = msvcdsp_project.left(dotFind);
+ msvcdsp_project.replace("-", "");
+
+ project->values("MSVCDSP_PROJECT").append(msvcdsp_project);
+
+ QStringList &proj = project->values("MSVCDSP_PROJECT");
+
+ for(QStringList::Iterator it = proj.begin(); it != proj.end(); ++it)
+ (*it).replace(QRegExp("\\.[a-zA-Z0-9_]*$"), "");
+
+ if(!project->values("QMAKE_APP_FLAG").isEmpty()) {
+ if(project->isActiveConfig("console")) {
+ project->values("MSVCDSP_TARGETTYPE").append("Console Application");
+ project->values("MSVCDSP_DSPTYPE").append("0x0103");
+ project->values("MSVCDSP_DEFINES").append(" /D \"_CONSOLE\" ");
+ } else {
+ project->values("MSVCDSP_TARGETTYPE").append("Application");
+ project->values("MSVCDSP_DSPTYPE").append("0x0101");
+ project->values("MSVCDSP_DEFINES").append(" /D \"_WINDOWS\" ");
+ }
+ } else {
+ if(project->isActiveConfig("dll")) {
+ project->values("MSVCDSP_TARGETTYPE").append("Dynamic-Link Library");
+ project->values("MSVCDSP_DSPTYPE").append("0x0102");
+ project->values("MSVCDSP_DEFINES").append(" /D \"_USRDLL\" ");
+ } else {
+ project->values("MSVCDSP_TARGETTYPE").append("Static Library");
+ project->values("MSVCDSP_DSPTYPE").append("0x0104");
+ project->values("MSVCDSP_DEFINES").append(" /D \"_LIB\" ");
+ }
+ }
+
+ project->values("MSVCDSP_LFLAGS") += project->values("QMAKE_LFLAGS");
+
+ if(!project->values("QMAKE_LIBDIR").isEmpty())
+ project->values("MSVCDSP_LFLAGS").append(valGlue(
+ escapeFilePaths(project->values("QMAKE_LIBDIR")),
+ "/LIBPATH:"," /LIBPATH:",""));
+
+ project->values("MSVCDSP_DEFINES").append(varGlue("DEFINES","/D ","" " /D ",""));
+ project->values("MSVCDSP_DEFINES").append(varGlue("PRL_EXPORT_DEFINES","/D ","" " /D ",""));
+ project->values("MSVCDSP_DEFINES").append(" /D \"WIN32\" ");
+
+ QStringList &libs = project->values("QMAKE_LIBS");
+ for(QStringList::Iterator libit = libs.begin(); libit != libs.end(); ++libit) {
+ project->values("MSVCDSP_LIBS").append(" " + escapeFilePath(*libit));
+ }
+
+ QStringList &incs = project->values("INCLUDEPATH");
+ for(QStringList::Iterator incit = incs.begin(); incit != incs.end(); ++incit) {
+ QString inc = (*incit);
+ project->values("MSVCDSP_INCPATH").append("/I" + escapeFilePath(inc));
+ }
+ project->values("MSVCDSP_INCPATH").append("/I" + escapeFilePath(specdir()));
+
+ QString dest;
+ QString preLinkStep;
+ QString postLinkStep;
+ QString copyDllStep;
+
+ if(!project->values("QMAKE_PRE_LINK").isEmpty())
+ preLinkStep += var("QMAKE_PRE_LINK");
+
+ if(!project->values("QMAKE_POST_LINK").isEmpty())
+ postLinkStep += var("QMAKE_POST_LINK");
+
+ // don't destroy the target, it is used by prl writer.
+ if(!project->values("DESTDIR").isEmpty()) {
+ dest = project->first("DESTDIR");
+ project->values("DESTDIR").first() = dest;
+ dest = project->values("TARGET").first() + project->first("TARGET_EXT");
+ dest.prepend(project->first("DESTDIR"));
+ Option::fixPathToTargetOS(dest);
+ dest = escapeFilePath(dest);
+
+ project->values("MSVCDSP_TARGET").append(
+ QString("/out:") + dest);
+ if(project->isActiveConfig("dll")) {
+ QString imp = dest;
+ imp.replace(".dll", ".lib");
+ project->values("MSVCDSP_TARGET").append(QString(" /implib:") + escapeFilePath(imp));
+ }
+ }
+
+ if(project->isActiveConfig("dll") && !project->values("DLLDESTDIR").isEmpty()) {
+ QStringList dlldirs = project->values("DLLDESTDIR");
+ if(dlldirs.count())
+ copyDllStep += "\t";
+ for(QStringList::Iterator dlldir = dlldirs.begin(); dlldir != dlldirs.end(); ++dlldir) {
+ copyDllStep += "copy \"$(TargetPath)\" " + escapeFilePath(Option::fixPathToTargetOS(*dlldir)) + "\t";
+ }
+ }
+
+ if(!preLinkStep.isEmpty()) {
+ project->values("MSVCDSP_PRE_LINK").append(
+ "# Begin Special Build Tool\n"
+ "SOURCE=$(InputPath)\n"
+ "PreLink_Desc=Post Build Step\n"
+ "PreLink_Cmds=" + preLinkStep + "\n"
+ "# End Special Build Tool\n");
+ }
+
+ if(!postLinkStep.isEmpty() || !copyDllStep.isEmpty()) {
+ project->values("MSVCDSP_POST_LINK").append(
+ "# Begin Special Build Tool\n"
+ "SOURCE=$(InputPath)\n"
+ "PostBuild_Desc=Post Build Step\n"
+ "PostBuild_Cmds=" + postLinkStep + copyDllStep + "\n"
+ "# End Special Build Tool\n");
+ }
+
+ QStringList &formList = project->values("FORMS");
+ for(QStringList::ConstIterator hit = formList.begin(); hit != formList.end(); ++hit) {
+ if(exists(*hit + ".h"))
+ project->values("SOURCES").append(*hit + ".h");
+ }
+ QStringList &form3List = project->values("FORMS3");
+ for(QStringList::ConstIterator hit = form3List.begin(); hit != form3List.end(); ++hit) {
+ if(exists(*hit + ".h"))
+ project->values("SOURCES").append(*hit + ".h");
+ }
+
+ project->values("QMAKE_INTERNAL_PRL_LIBS") << "MSVCDSP_LIBS";
+
+ // Move some files around //### is this compat?
+ if (!project->values("IMAGES").isEmpty()) {
+ QString imageFactory(project->first("QMAKE_IMAGE_COLLECTION"));
+ project->values("GENERATED_SOURCES") += imageFactory;
+ project->values("SOURCES").removeAll(imageFactory);
+ }
+
+ // Setup PCH variables
+ precompH = project->first("PRECOMPILED_HEADER");
+ namePCH = fileInfo(precompH).fileName();
+ usePCH = !precompH.isEmpty() && project->isActiveConfig("precompile_header");
+ if (usePCH) {
+ // Created files
+ precompObj = var("PRECOMPILED_DIR") + project->first("TARGET") + "_pch" + Option::obj_ext;
+ precompPch = var("PRECOMPILED_DIR") + project->first("TARGET") + "_pch.pch";
+
+ // Add PRECOMPILED_HEADER to HEADERS
+ if (!project->values("HEADERS").contains(precompH))
+ project->values("HEADERS") += precompH;
+ // Add precompile compiler options
+ project->values("PRECOMPILED_FLAGS") = QStringList("/Fp" + precompPch + " /Yu" + escapeFilePath(namePCH) + " /FI" + escapeFilePath(namePCH) + " ");
+ // Return to variable pool
+ project->values("PRECOMPILED_OBJECT") = QStringList(precompObj);
+ project->values("PRECOMPILED_PCH") = QStringList(precompPch);
+ }
+
+ QString buildName;
+ if (!var("BUILD_NAME").isEmpty())
+ buildName = var("BUILD_NAME");
+ else if (project->isActiveConfig("debug"))
+ buildName = "Debug";
+ else
+ buildName = "Release";
+
+ project->values("MSVCDSP_CONFIG_NAME") = QStringList(" - " + platform + " " + buildName);
+}
+
+void DspMakefileGenerator::processPrlVariable(const QString &var, const QStringList &l)
+{
+ if(var == "QMAKE_PRL_DEFINES") {
+ QStringList &out = project->values("MSVCDSP_DEFINES");
+ for(QStringList::ConstIterator it = l.begin(); it != l.end(); ++it) {
+ if(out.indexOf((*it)) == -1)
+ out.append((" /D \"" + *it + "\""));
+ }
+ } else {
+ MakefileGenerator::processPrlVariable(var, l);
+ }
+}
+
+bool DspMakefileGenerator::openOutput(QFile &file, const QString &build) const
+{
+ QString outdir;
+ if(!file.fileName().isEmpty()) {
+ if(QDir::isRelativePath(file.fileName()))
+ file.setFileName(Option::output_dir + "/" + file.fileName()); //pwd when qmake was run
+ QFileInfo fi(fileInfo(file.fileName()));
+ if(fi.isDir())
+ outdir = file.fileName() + QDir::separator();
+ }
+
+ if(!outdir.isEmpty() || file.fileName().isEmpty()) {
+ QString ext = project->first("DSP_EXTENSION");
+ if(project->first("TEMPLATE") == "vcsubdirs") {
+ if (!project->first("DSW_EXTENSION").isEmpty())
+ ext = project->first("DSW_EXTENSION");
+ else
+ ext = ".dsw";
+ }
+ QString outputName = unescapeFilePath(project->first("QMAKE_DSP_PROJECT_NAME"));
+ if (!project->first("MAKEFILE").isEmpty())
+ outputName = unescapeFilePath(project->first("MAKEFILE"));
+ if (outputName.isEmpty())
+ outputName = unescapeFilePath(project->first("QMAKE_ORIG_TARGET"));
+ file.setFileName(outdir + outputName + ext);
+ }
+
+ if(QDir::isRelativePath(file.fileName())) {
+ QString ofile = Option::fixPathToLocalOS(file.fileName());
+ int slashfind = ofile.lastIndexOf(Option::dir_sep);
+ if(slashfind == -1) {
+ ofile = ofile.replace(QRegExp("-"), "_");
+ } else {
+ int hypenfind = ofile.indexOf('-', slashfind);
+ while (hypenfind != -1 && slashfind < hypenfind) {
+ ofile = ofile.replace(hypenfind, 1, "_");
+ hypenfind = ofile.indexOf('-', hypenfind + 1);
+ }
+ }
+ file.setFileName(Option::fixPathToLocalOS(qmake_getpwd() + Option::dir_sep + ofile));
+ }
+ return Win32MakefileGenerator::openOutput(file, build);
+}
+
+bool DspMakefileGenerator::mergeBuildProject(MakefileGenerator *other)
+{
+
+ mergedProjects.prepend(static_cast<DspMakefileGenerator*>(other));
+ return true;
+}
+
+bool DspMakefileGenerator::writeProjectMakefile()
+{
+ bool ret = true;
+
+ QTextStream t(&Option::output);
+ // Check if all requirements are fulfilled
+ if(!project->values("QMAKE_FAILED_REQUIREMENTS").isEmpty()) {
+ fprintf(stderr, "Project file not generated because all requirements not met:\n\t%s\n",
+ var("QMAKE_FAILED_REQUIREMENTS").toLatin1().constData());
+ return true;
+ }
+
+ // Generate project file
+ if(project->first("TEMPLATE") == "vcapp" ||
+ project->first("TEMPLATE") == "vclib") {
+ if (!mergedProjects.count()) {
+ warn_msg(WarnLogic, "Generator: MSVC DSP: no single configuration created, cannot output project!");
+ return false;
+ }
+ debug_msg(1, "Generator: MSVC 6: Writing project file");
+
+ writeDspHeader(t);
+ for (int i = 0; i < mergedProjects.count(); ++i) {
+ DspMakefileGenerator* config = mergedProjects.at(i);
+ t << endl;
+ if (i == 0)
+ t << "!IF";
+ else
+ t << "!ELSEIF";
+ t << " \"$(CFG)\" == \"" << configName(config) << "\"" << endl;
+ t << endl;
+ writeDspConfig(t, config);
+ }
+ t << endl;
+ t << "!ENDIF " << endl;
+ t << endl;
+ t << "# Begin Target" << endl;
+ t << endl;
+ for (int i = 0; i < mergedProjects.count(); ++i)
+ t << "# Name \"" << configName(mergedProjects.at(i)) << "\"" << endl;
+ t << endl;
+
+ QMap< QString, QSet<QString> > files;
+
+ // merge source files
+ for (int i = 0; i < mergedProjects.count(); ++i) {
+
+ DspMakefileGenerator* config = mergedProjects.at(i);
+
+ files["DEF_FILE"] += config->project->values("DEF_FILE").toSet();
+ files["SOURCES"] += config->project->values("SOURCES").toSet();
+ files["HEADERS"] += config->project->values("HEADERS").toSet();
+ files["INTERFACES"] += config->project->values("INTERFACES").toSet();
+ files["FORMS"] += config->project->values("FORMS").toSet();
+ files["FORMS"] += config->project->values("FORMS3").toSet();
+ files["IMAGES"] += config->project->values("IMAGES").toSet();
+ files["RC_FILE"] += config->project->values("RC_FILE").toSet();
+ files["RESOURCES"] += config->project->values("RESOURCES").toSet();
+ files["TRANSLATIONS"] += config->project->values("TRANSLATIONS").toSet();
+ files["LEXSOURCES"] += config->project->values("LEXSOURCES").toSet();
+ files["YACCSOURCES"] += config->project->values("YACCSOURCES").toSet();
+ files["TYPELIBS"] += config->project->values("TYPELIBS").toSet();
+
+ if (!config->project->isEmpty("QMAKE_EXTRA_COMPILERS")) {
+ const QStringList &quc = config->project->values("QMAKE_EXTRA_COMPILERS");
+ for (QStringList::ConstIterator it = quc.begin(); it != quc.end(); ++it) {
+ const QStringList &inputs = project->values((*it)+".input");
+ for (QStringList::ConstIterator input = inputs.begin(); input != inputs.end(); ++input) {
+ if (*input != "UIC3_HEADERS")
+ files[(*input)] += config->project->values((*input)).toSet();
+ }
+ }
+ }
+ }
+
+ QStringList keys = files.keys();
+ for (int k = 0; k < keys.size(); ++k)
+ project->values(keys.at(k)) = QList<QString>::fromSet(files[keys.at(k)]);
+
+ QStringList listNames = QString("SOURCES|DEF_FILE").split("|");
+ QStringList allListNames = listNames;
+ writeFileGroup(t, listNames, "Source Files", "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat");
+ listNames = QStringList("HEADERS");
+ allListNames += listNames;
+ writeFileGroup(t, listNames, "Header Files", "h;hpp;hxx;hm;inl");
+ listNames = QString("FORMS|INTERFACES|FORMS3").split("|");
+ allListNames += listNames;
+ writeFileGroup(t, listNames, "Form Files", "ui");
+ listNames = QStringList("IMAGES");
+ allListNames += listNames;
+ writeFileGroup(t, listNames, "Image Files", "");
+ listNames = QString("RC_FILE|RESOURCES").split("|");
+ allListNames += listNames;
+ writeFileGroup(t, listNames, "Resources", "rc;qrc");
+ listNames = QStringList("TRANSLATIONS");
+ allListNames += listNames;
+ writeFileGroup(t, listNames, "Translations", "ts;xlf");
+ listNames = QStringList("LEXSOURCES");
+ allListNames += listNames;
+ writeFileGroup(t, listNames, "Lexables", "l");
+ listNames = QStringList("YACCSOURCES");
+ allListNames += listNames;
+ writeFileGroup(t, listNames, "Yaccables", "y");
+ listNames = QStringList("TYPELIBS");
+ allListNames += listNames;
+ writeFileGroup(t, listNames, "Type Libraries", "tlb;olb");
+
+ for (int l = 0; l < allListNames.size(); ++l)
+ keys.removeAll(allListNames.at(l));
+
+ for (int k = 0; k < keys.size(); ++k)
+ writeFileGroup(t, QStringList(keys.at(k)), keys.at(k) + " Files", "");
+
+ // done last as generated may have changed when creating build rules for the above
+ for (int i = 0; i < mergedProjects.count(); ++i) {
+
+ DspMakefileGenerator* config = mergedProjects.at(i);
+
+ config->project->values("SWAPPED_BUILD_STEPS") = config->swappedBuildSteps.keys();
+ files["SWAPPED_BUILD_STEPS"] += config->project->values("SWAPPED_BUILD_STEPS").toSet();
+
+ files["GENERATED_SOURCES"] += config->project->values("GENERATED_SOURCES").toSet();
+ files["GENERATED_FILES"] += config->project->values("GENERATED_FILES").toSet();
+ }
+
+ project->values("SWAPPED_BUILD_STEPS") = QList<QString>::fromSet(files["SWAPPED_BUILD_STEPS"]);
+ project->values("GENERATED_SOURCES") = QList<QString>::fromSet(files["GENERATED_SOURCES"]);
+ project->values("GENERATED_FILES") = QList<QString>::fromSet(files["GENERATED_FILES"]);
+
+ writeFileGroup(t, QString("GENERATED_SOURCES|GENERATED_FILES|SWAPPED_BUILD_STEPS").split("|"), "Generated", "");
+ t << endl;
+ t << "# End Target" << endl;
+ t << "# End Project" << endl;
+ }else if(project->first("TEMPLATE") == "vcsubdirs") {
+ ret = writeMakefile(t);
+ }
+
+ return ret;
+}
+
+const char _dswHeader60[] = "Microsoft Developer Studio Workspace File, Format Version 6.00\n";
+const char _dswWarning[] = "# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!\n";
+const char _dswDevider[] = "###############################################################################\n";
+const char _dswProjectName[] = "Project: \"%1\"=%2 - Package Owner=<4>\n"; // %1 = project name, %2 = project path
+const char _dswPackage5Start[] = "Package=<5>\n{{{\n";
+const char _dswPackage5Stop[] = "}}}\n";
+const char _dswPackage4Start[] = "Package=<4>\n{{{\n";
+const char _dswPackage4Stop[] = "}}}\n";
+const char _dswProjectDep[] = " Begin Project Dependency\n Project_Dep_Name %1\n End Project Dependency\n"; // %1 = project name
+const char _dswGlobal[] = "Global:\n\nPackage=<5>\n{{{\n}}}\n\nPackage=<3>\n{{{\n}}}\n\n";
+
+
+struct WorkspaceDepend {
+ QString dspProjectFile, orig_target, target;
+ QStringList dependencies;
+};
+
+void DspMakefileGenerator::writeSubDirs(QTextStream &t)
+{
+ // Output headers
+ t << _dswHeader60;
+ t << _dswWarning;
+ t << endl;
+
+ QHash<QString, WorkspaceDepend*> workspace_depends;
+ QList<WorkspaceDepend*> workspace_cleanup;
+ QStringList subdirs = project->values("SUBDIRS");
+ QString oldpwd = qmake_getpwd();
+
+ // Make sure that all temp projects are configured
+ // for release so that the depends are created
+ // without the debug <lib>dxxx.lib name mangling
+ QStringList old_after_vars = Option::after_user_vars;
+ Option::after_user_vars.append("CONFIG+=release");
+
+ for(int i = 0; i < subdirs.size(); ++i) {
+ QString tmp = subdirs.at(i);
+ if(!project->isEmpty(tmp + ".file")) {
+ if(!project->isEmpty(tmp + ".subdir"))
+ warn_msg(WarnLogic, "Cannot assign both file and subdir for subdir %s",
+ tmp.toLatin1().constData());
+ tmp = project->first(tmp + ".file");
+ } else if(!project->isEmpty(tmp + ".subdir")) {
+ tmp = project->first(tmp + ".subdir");
+ }
+
+ QFileInfo fi(fileInfo(Option::fixPathToLocalOS(tmp, true)));
+ if(fi.exists()) {
+ if(fi.isDir()) {
+ QString profile = tmp;
+ if(!profile.endsWith(Option::dir_sep))
+ profile += Option::dir_sep;
+ profile += fi.baseName() + ".pro";
+ subdirs.append(profile);
+ } else {
+ QMakeProject tmp_proj;
+ QString dir = fi.path(), fn = fi.fileName();
+ if(!dir.isEmpty()) {
+ if(!qmake_setpwd(dir))
+ fprintf(stderr, "Cannot find directory: %s\n", dir.toLatin1().constData());
+ }
+ if(tmp_proj.read(fn)) {
+ // Check if all requirements are fulfilled
+ if(!tmp_proj.variables()["QMAKE_FAILED_REQUIREMENTS"].isEmpty()) {
+ fprintf(stderr, "Project file(%s) not added to Workspace because all requirements not met:\n\t%s\n",
+ fn.toLatin1().constData(), tmp_proj.values("QMAKE_FAILED_REQUIREMENTS").join(" ").toLatin1().constData());
+ continue;
+ }
+ if(tmp_proj.first("TEMPLATE") == "vcsubdirs") {
+ QStringList tmp_proj_subdirs = tmp_proj.variables()["SUBDIRS"];
+ for(int x = 0; x < tmp_proj_subdirs.size(); ++x) {
+ QString tmpdir = tmp_proj_subdirs.at(x);
+ if(!tmp_proj.isEmpty(tmpdir + ".file")) {
+ if(!tmp_proj.isEmpty(tmpdir + ".subdir"))
+ warn_msg(WarnLogic, "Cannot assign both file and subdir for subdir %s",
+ tmpdir.toLatin1().constData());
+ tmpdir = tmp_proj.first(tmpdir + ".file");
+ } else if(!tmp_proj.isEmpty(tmpdir + ".subdir")) {
+ tmpdir = tmp_proj.first(tmpdir + ".subdir");
+ }
+ subdirs += fileFixify(tmpdir);
+ }
+ } else if(tmp_proj.first("TEMPLATE") == "vcapp" || tmp_proj.first("TEMPLATE") == "vclib") {
+ // Initialize a 'fake' project to get the correct variables
+ // and to be able to extract all the dependencies
+ DspMakefileGenerator tmp_dsp;
+ tmp_dsp.setNoIO(true);
+ tmp_dsp.setProjectFile(&tmp_proj);
+ if(Option::debug_level) {
+ QMap<QString, QStringList> &vars = tmp_proj.variables();
+ for(QMap<QString, QStringList>::Iterator it = vars.begin();
+ it != vars.end(); ++it) {
+ if(it.key().left(1) != "." && !it.value().isEmpty())
+ debug_msg(1, "%s: %s === %s", fn.toLatin1().constData(), it.key().toLatin1().constData(),
+ it.value().join(" :: ").toLatin1().constData());
+ }
+ }
+
+ // We assume project filename is [QMAKE_ORIG_TARGET].vcproj
+ QString dsp = unescapeFilePath(tmp_dsp.project->first("MSVCDSP_PROJECT") + project->first("DSP_EXTENSION"));
+
+ // If file doesn't exsist, then maybe the users configuration
+ // doesn't allow it to be created. Skip to next...
+ if(!exists(qmake_getpwd() + Option::dir_sep + dsp)) {
+ warn_msg(WarnLogic, "Ignored (not found) '%s'", QString(qmake_getpwd() + Option::dir_sep + dsp).toLatin1().constData());
+ goto nextfile; // # Dirty!
+ }
+
+ WorkspaceDepend *newDep = new WorkspaceDepend;
+ newDep->dspProjectFile = fileFixify(dsp);
+ newDep->orig_target = unescapeFilePath(tmp_proj.first("QMAKE_ORIG_TARGET"));
+ newDep->target = tmp_proj.first("MSVCDSP_PROJECT").section(Option::dir_sep, -1) + tmp_proj.first("TARGET_EXT");
+
+ // We want to store it as the .lib name.
+ if(newDep->target.endsWith(".dll"))
+ newDep->target = newDep->target.left(newDep->target.length()-3) + "lib";
+
+ // All projects having mocable sourcefiles are dependent on moc.exe
+ if(tmp_proj.variables()["CONFIG"].contains("moc"))
+ newDep->dependencies << "moc.exe";
+
+ // All extra compilers which has valid input are considered dependencies
+ const QStringList &quc = tmp_proj.variables()["QMAKE_EXTRA_COMPILERS"];
+ for(QStringList::ConstIterator it = quc.constBegin(); it != quc.constEnd(); ++it) {
+ const QStringList &invar = tmp_proj.variables().value((*it) + ".input");
+ for(QStringList::ConstIterator iit = invar.constBegin(); iit != invar.constEnd(); ++iit) {
+ const QStringList fileList = tmp_proj.variables().value(*iit);
+ if (!fileList.isEmpty()) {
+ QString dep = tmp_proj.first((*it) + ".commands").section('/', -1).section('\\', -1);
+ if (!newDep->dependencies.contains(dep))
+ newDep->dependencies << dep;
+ }
+ }
+ }
+
+ // Add all unknown libs to the deps
+ QStringList where("QMAKE_LIBS");
+ if(!tmp_proj.isEmpty("QMAKE_INTERNAL_PRL_LIBS"))
+ where = tmp_proj.variables()["QMAKE_INTERNAL_PRL_LIBS"];
+
+ for(QStringList::iterator wit = where.begin();
+ wit != where.end(); ++wit) {
+ QStringList &l = tmp_proj.variables()[(*wit)];
+ for(QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
+ QString opt = (*it).trimmed();
+ if(!opt.startsWith("/") && // Not a switch
+ opt != newDep->target && // Not self
+ opt != "opengl32.lib" && // We don't care about these libs
+ opt != "glu32.lib" && // to make depgen alittle faster
+ opt != "kernel32.lib" &&
+ opt != "user32.lib" &&
+ opt != "gdi32.lib" &&
+ opt != "comdlg32.lib" &&
+ opt != "advapi32.lib" &&
+ opt != "shell32.lib" &&
+ opt != "ole32.lib" &&
+ opt != "oleaut32.lib" &&
+ opt != "uuid.lib" &&
+ opt != "imm32.lib" &&
+ opt != "winmm.lib" &&
+ opt != "wsock32.lib" &&
+ opt != "ws2_32.lib" &&
+ opt != "winspool.lib" &&
+ opt != "delayimp.lib")
+ {
+ newDep->dependencies << opt.section(Option::dir_sep, -1);
+ }
+ }
+ }
+ workspace_cleanup.append(newDep);
+ workspace_depends.insert(newDep->target, newDep);
+
+ debug_msg(1, "Generator: MSVC: Added project (name:'%s' path:'%s' deps:'%s')",
+ qPrintable(newDep->target) , qPrintable(newDep->dspProjectFile),
+ qPrintable(newDep->dependencies.join(";")));
+ }
+ }
+nextfile:
+ qmake_setpwd(oldpwd);
+ }
+ }
+ }
+
+ // Restore previous after_user_var options
+ Option::after_user_vars = old_after_vars;
+
+ // Output all projects
+ QString dswProjectName = QLatin1String(_dswProjectName);
+ QString dswProjectDep = QLatin1String(_dswProjectDep);
+ for(QList<WorkspaceDepend*>::Iterator it = workspace_cleanup.begin(); it != workspace_cleanup.end(); ++it) {
+ t << _dswDevider;
+ t << endl;
+ t << dswProjectName.arg((*it)->orig_target).arg((*it)->dspProjectFile);
+ t << endl;
+ t << _dswPackage5Start;
+ t << _dswPackage5Stop;
+ t << endl;
+ t << _dswPackage4Start;
+
+ // Output project dependencies
+ for(QStringList::iterator dit = (*it)->dependencies.begin(); dit != (*it)->dependencies.end(); ++dit) {
+ if(WorkspaceDepend *vc = workspace_depends[*dit])
+ t << dswProjectDep.arg(vc->orig_target);
+ }
+
+ t << _dswPackage4Stop;
+ }
+
+ // Output global part
+ t << _dswDevider << endl;
+ t << _dswGlobal;
+ t << _dswDevider;
+ t << endl << endl;
+}
+
+class FolderGroup
+{
+public:
+ QString name;
+ QString filter;
+ QMap<QString, FolderGroup *> subFolders;
+ QMap<QString, QString> files;
+
+ void insertStructured(const QString &file, const QString &fileListName)
+ {
+ QStringList path = QFileInfo(file).path().split("/");
+ if (!path.isEmpty() && path.at(0) == ".")
+ path.takeAt(0);
+ FolderGroup *currentFolder = this;
+ for (int i = 0; i < path.size(); i++) {
+ if (currentFolder->subFolders.contains(path.at(i))) {
+ currentFolder = currentFolder->subFolders.value(path.at(i));
+ } else {
+ FolderGroup *newFolder = new FolderGroup;
+ newFolder->name = path.at(i);
+ currentFolder->subFolders.insert(path.at(i), newFolder);
+ currentFolder = newFolder;
+ }
+ }
+ currentFolder->files.insert(file, fileListName);
+ }
+
+ void insertFlat(const QString &file, const QString &fileListName)
+ {
+ files.insert(file, fileListName);
+ }
+
+ ~FolderGroup()
+ {
+ qDeleteAll(subFolders.values());
+ }
+};
+
+bool DspMakefileGenerator::writeFileGroup(QTextStream &t, const QStringList &listNames, const QString &group, const QString &filter)
+{
+ FolderGroup root;
+ root.name = group;
+ root.filter = filter;
+
+ for (int i = 0; i < listNames.count(); ++i) {
+ QStringList list = project->values(listNames.at(i));
+ for (int j = 0; j < list.count(); ++j) {
+ const QString name = list.at(j);
+ if (name.isEmpty())
+ continue;
+ if (project->isActiveConfig("flat"))
+ root.insertFlat(name, listNames.at(i));
+ else
+ root.insertStructured(name, listNames.at(i));
+ }
+ }
+
+ if (root.files.isEmpty() && root.subFolders.isEmpty())
+ return true;
+
+ writeSubFileGroup(t, &root);
+
+ return true;
+}
+
+void DspMakefileGenerator::writeSubFileGroup(QTextStream &t, FolderGroup *folder)
+{
+ t << "# Begin Group \"" << folder->name << "\"" << endl;
+ t << "# PROP Default_Filter \"" << folder->filter << "\"" << endl;
+ QMap<QString, FolderGroup *>::const_iterator folderIt = folder->subFolders.begin();
+ while (folderIt != folder->subFolders.end()) {
+ writeSubFileGroup(t, folderIt.value());
+ ++folderIt;
+ }
+ QMap<QString, QString>::const_iterator it = folder->files.begin();
+ while (it != folder->files.end()) {
+ t << "# Begin Source File" << endl;
+ t << "SOURCE=" << escapeFilePath(it.key()) << endl;
+ writeBuildstepForFile(t, it.key(), it.value());
+ t << "# End Source File" << endl;
+ t << endl;
+ ++it;
+ }
+ t << "# End Group" << endl;
+ t << endl;
+}
+
+bool DspMakefileGenerator::writeBuildstepForFile(QTextStream &t, const QString &file, const QString &listName)
+{
+
+ if (!mergedProjects.count()) {
+ t << writeBuildstepForFileForConfig(file, listName, this);
+ return true;
+ }
+
+ //only add special build rules when needed
+
+ QStringList specialBuilds;
+ int i = 0;
+ for (i = 0; i < mergedProjects.count(); ++i)
+ specialBuilds += writeBuildstepForFileForConfig(file, listName, mergedProjects.at(i));
+
+ // no special build just return
+ if (specialBuilds.join("").isEmpty())
+ return true;
+
+ for (i = 0; i < mergedProjects.count(); ++i) {
+ if (i == 0)
+ t << "!IF";
+ else
+ t << "!ELSEIF";
+ t << " \"$(CFG)\" == \"" << configName(mergedProjects.at(i)) << "\"" << endl;
+ t << endl;
+ t << specialBuilds.at(i);
+ t << endl;
+ }
+
+ t << "!ENDIF" << endl;
+
+ return true;
+}
+
+bool DspMakefileGenerator::writeDspConfig(QTextStream &t, DspMakefileGenerator *config)
+{
+
+ bool isDebug = config->project->isActiveConfig("debug");
+ bool staticLibTarget = config->var("MSVCDSP_DSPTYPE") == "0x0104";
+
+ QString outDir = Option::fixPathToTargetOS(config->project->first("DESTDIR"));
+ while (outDir.endsWith(Option::dir_sep))
+ outDir.chop(1);
+ outDir = config->escapeFilePath(outDir);
+
+ QString intDir = config->project->first("OBJECTS_DIR");
+ while (intDir.endsWith(Option::dir_sep))
+ intDir.chop(1);
+ intDir = config->escapeFilePath(intDir);
+
+ t << "# PROP BASE Use_MFC 0" << endl;
+ t << "# PROP BASE Use_Debug_Libraries " << (isDebug ? "1" : "0") << endl;
+ t << "# PROP BASE Output_Dir " << outDir << endl;
+ t << "# PROP BASE Intermediate_Dir " << intDir << endl;
+ t << "# PROP BASE Target_Dir \"\"" << endl;
+ t << "# PROP Use_MFC 0" << endl;
+ t << "# PROP Use_Debug_Libraries " << (isDebug ? "1" : "0") << endl;
+
+ t << "# PROP Output_Dir " << outDir << endl;
+ t << "# PROP Intermediate_Dir " << intDir << endl;
+ if (config->project->isActiveConfig("dll") || config->project->isActiveConfig("plugin"))
+ t << "# PROP Ignore_Export_Lib 1" << endl;
+ t << "# PROP Target_Dir \"\"" << endl;
+ t << "# ADD CPP " << config->var("MSVCDSP_INCPATH") << " /c /FD " << config->var("QMAKE_CXXFLAGS") << " " << config->var("MSVCDSP_DEFINES") << " " << config->var("PRECOMPILED_FLAGS") << endl;
+ t << "# ADD MTL /nologo /mktyplib203 /win32 /D " << (isDebug ? "\"_DEBUG\"" : "\"NDEBUG\"") << endl;
+ t << "# ADD RSC /l 0x409 /d " << (isDebug ? "\"_DEBUG\"" : "\"NDEBUG\"") << endl;
+ t << "# ADD BSC32 /nologo" << endl;
+ if (staticLibTarget) {
+ t << "LIB32=" << config->var("QMAKE_LIB") << endl;
+ t << "# ADD LIB32 " << config->var("MSVCDSP_TARGET") << " " << config->var("PRECOMPILED_OBJECT") << endl;
+ } else {
+ t << "LINK32=" << config->var("QMAKE_LINK") << endl;
+ t << "# ADD LINK32 " << config->var("MSVCDSP_LFLAGS") << " " << config->var("MSVCDSP_LIBS") << " " << config->var("MSVCDSP_TARGET") << " " << config->var("PRECOMPILED_OBJECT") << endl;
+ }
+
+ if (!config->project->values("MSVCDSP_PRE_LINK").isEmpty())
+ t << config->project->values("MSVCDSP_PRE_LINK").first();
+
+ if (!config->project->values("MSVCDSP_POST_LINK").isEmpty())
+ t << config->project->values("MSVCDSP_POST_LINK").first();
+
+ return true;
+}
+
+QString DspMakefileGenerator::writeBuildstepForFileForConfig(const QString &file, const QString &listName, DspMakefileGenerator *config)
+{
+ QString ret;
+ QTextStream t(&ret);
+
+ // exclude from build
+ if (!config->project->values(listName).contains(file)) {
+ t << "# PROP Exclude_From_Build 1" << endl;
+ return ret;
+ }
+
+ if (config->usePCH) {
+ bool c_file = false;
+ for (QStringList::Iterator it = Option::c_ext.begin(); it != Option::c_ext.end(); ++it) {
+ if (file.endsWith(*it)) {
+ c_file = true;
+ break;
+ }
+ }
+ if(c_file) {
+ t << "# SUBTRACT CPP /FI" << config->escapeFilePath(config->namePCH) << " /Yu" << config->escapeFilePath(config->namePCH) << " /Fp" << endl;
+ return ret;
+ } else if (config->precompH.endsWith(file)) {
+ // ### dependency list quickly becomes too long for VS to grok...
+ t << "USERDEP_" << file << "=" << config->valGlue(config->escapeFilePaths(config->findDependencies(config->precompH)), "", "\t", "") << endl;
+ t << endl;
+ t << "# Begin Custom Build - Creating precompiled header from " << file << "..." << endl;
+ t << "InputPath=.\\" << config->escapeFilePath(file) << endl << endl;
+ t << config->precompPch + ": $(SOURCE) \"$(IntDir)\" \"$(OUTDIR)\"" << endl;
+ t << "\t" << config->var("QMAKE_CC") << " /TP /W3 /FD /c /Yc /Fp" << config->precompPch << " /Fo" << config->precompObj << " /Fd\"$(IntDir)\\\\\" " << file << " ";
+ t << config->var("MSVCDSP_INCPATH") << " " << config->var("MSVCDSP_DEFINES") << " " << config->var("QMAKE_CXXFLAGS") << endl;
+ t << "# End Custom Build" << endl << endl;
+ return ret;
+ }
+ }
+
+ QString fileBase = QFileInfo(file).completeBaseName();
+
+ bool hasBuiltin = config->hasBuiltinCompiler(file);
+ BuildStep allSteps;
+
+ if (!config->swappedBuildSteps.contains(file)) {
+ QStringList compilers = config->project->values("QMAKE_EXTRA_COMPILERS");
+ for (int i = 0; i < compilers.count(); ++i) {
+ QString compiler = compilers.at(i);
+ if (config->project->values(compiler + ".input").isEmpty())
+ continue;
+ QString input = config->project->values(compiler + ".input").first();
+ QStringList inputList = config->project->values(input);
+ if (!inputList.contains(file))
+ continue;
+
+ QStringList compilerCommands = config->project->values(compiler + ".commands");
+ QStringList compilerOutput = config->project->values(compiler + ".output");
+ if (compilerCommands.isEmpty() || compilerOutput.isEmpty())
+ continue;
+
+ QStringList compilerName = config->project->values(compiler + ".name");
+ if (compilerName.isEmpty())
+ compilerName << compiler;
+ QStringList compilerDepends = config->project->values(compiler + ".depends");
+ QString compilerDependsCommand = config->project->values(compiler + ".depend_command").join(" ");
+ if (!compilerDependsCommand.isEmpty()) {
+ if(!config->canExecute(compilerDependsCommand))
+ compilerDependsCommand = QString();
+ }
+ QStringList compilerConfig = config->project->values(compiler + ".CONFIG");
+
+ if (!config->verifyExtraCompiler(compiler, file))
+ continue;
+
+ bool combineAll = compilerConfig.contains("combine");
+ if (combineAll && inputList.first() != file)
+ continue;
+
+ QString fileIn("$(InputPath)");
+
+ if (combineAll && !inputList.isEmpty()) {
+ fileIn = inputList.join(" ");
+ compilerDepends += inputList;
+ }
+
+ QString fileOut = compilerOutput.first();
+ QString fileOutBase = QFileInfo(fileOut).completeBaseName();
+ fileOut.replace("${QMAKE_FILE_IN}", fileIn);
+ fileOut.replace("${QMAKE_FILE_BASE}", fileBase);
+ fileOut.replace("${QMAKE_FILE_OUT_BASE}", fileOutBase);
+ fileOut.replace('/', '\\');
+
+ BuildStep step;
+ for (int i2 = 0; i2 < compilerDepends.count(); ++i2) {
+ QString dependency = compilerDepends.at(i2);
+ dependency.replace("${QMAKE_FILE_IN}", fileIn);
+ dependency.replace("${QMAKE_FILE_BASE}", fileBase);
+ dependency.replace("${QMAKE_FILE_OUT_BASE}", fileOutBase);
+ dependency.replace('/', '\\');
+ if (!step.deps.contains(dependency, Qt::CaseInsensitive))
+ step.deps << dependency;
+ }
+ // depends command
+ if (!compilerDependsCommand.isEmpty() && config->doDepends()) {
+ char buff[256];
+ QString dep_cmd = config->replaceExtraCompilerVariables(compilerDependsCommand, file,
+ fileOut);
+ dep_cmd = Option::fixPathToLocalOS(dep_cmd, true, false);
+ if(config->canExecute(dep_cmd)) {
+ if(FILE *proc = QT_POPEN(dep_cmd.toLatin1().constData(), "r")) {
+ QString indeps;
+ while(!feof(proc)) {
+ int read_in = (int)fread(buff, 1, 255, proc);
+ if(!read_in)
+ break;
+ indeps += QByteArray(buff, read_in);
+ }
+ QT_PCLOSE(proc);
+ if(!indeps.isEmpty())
+ step.deps += config->fileFixify(indeps.replace('\n', ' ').simplified().split(' '));
+ }
+ }
+ }
+
+
+ QString mappedFile;
+ if (hasBuiltin) {
+ mappedFile = fileOut;
+ fileOut = fileIn;
+ fileIn = file;
+ }
+
+ step.buildStep += " \\\n\t";
+ QString command(compilerCommands.join(" "));
+ // Replace any newlines with proper line-continuance
+ command.replace("\n", " \\\n\t");
+ // Might be a macro, and not a valid filename, so the replaceExtraCompilerVariables() would eat it
+ command.replace("${QMAKE_FILE_IN}", config->escapeFilePath(fileIn));
+ command.replace("${QMAKE_FILE_BASE}", config->escapeFilePath(fileBase));
+ command.replace("${QMAKE_FILE_OUT_BASE}", config->escapeFilePath(fileOutBase));
+ command.replace("${QMAKE_FILE_OUT}", config->escapeFilePath(fileOut));
+
+ command = config->replaceExtraCompilerVariables(command, fileIn, fileOut);
+
+ step.buildName = compilerName.first();
+ step.buildStep += command;
+ step.buildOutputs += fileOut;
+
+ if (hasBuiltin) {
+ step.deps << fileIn;
+ config->swappedBuildSteps[mappedFile] = step;
+ } else {
+ allSteps << step;
+ }
+ }
+ } else {
+ allSteps << config->swappedBuildSteps.value(file);
+ }
+
+ if (allSteps.buildStep.isEmpty())
+ return ret;
+
+ int i;
+ QStringList dependencyList;
+ // remove dependencies that are also output
+ for (i = 0; i < 1; ++i) {
+ QStringList buildOutput(allSteps.buildOutputs.at(i));
+
+ for (int i2 = 0; i2 < allSteps.deps.count(); ++i2) {
+ QString dependency = allSteps.deps.at(i2);
+ if (!buildOutput.contains(dependency) && !dependencyList.contains(dependency))
+ dependencyList << dependency;
+ }
+ }
+ QString allDependencies = config->valGlue(dependencyList, "", "\t", "");
+ t << "USERDEP_" << file << "=" << allDependencies << endl;
+ t << "# PROP Ignore_Default_Tool 1" << endl;
+ t << "# Begin Custom Build - Running " << allSteps.buildName << " on " << file << endl;
+ t << "InputPath=" << file << endl;
+ t << "BuildCmds= " << allSteps.buildStep << endl;
+ for (i = 0; i < allSteps.buildOutputs.count(); ++i) {
+ t << config->escapeFilePath(allSteps.buildOutputs.at(i))
+ << " : $(SOURCE) $(INTDIR) $(OUTDIR)\n\t$(BuildCmds)\n";
+ }
+ t << endl;
+ t << "# End Custom Build" << endl;
+
+ return ret;
+}
+
+QT_END_NAMESPACE
diff --git a/qmake/generators/win32/msvc_dsp.h b/qmake/generators/win32/msvc_dsp.h
new file mode 100644
index 0000000..a870976
--- /dev/null
+++ b/qmake/generators/win32/msvc_dsp.h
@@ -0,0 +1,122 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef MSVC_DSP_H
+#define MSVC_DSP_H
+
+#include "winmakefile.h"
+
+QT_BEGIN_NAMESPACE
+
+class FolderGroup;
+
+class DspMakefileGenerator : public Win32MakefileGenerator
+{
+ bool init_flag;
+ bool writeDspHeader(QTextStream &);
+ bool writeDspParts(QTextStream &);
+ bool writeFileGroup(QTextStream &t, const QStringList &listNames, const QString &group, const QString &filter);
+ void writeSubFileGroup(QTextStream &t, FolderGroup *folder);
+ bool writeBuildstepForFile(QTextStream &t, const QString &file, const QString &listName);
+ static bool writeDspConfig(QTextStream &t, DspMakefileGenerator *config);
+ static QString writeBuildstepForFileForConfig(const QString &file, const QString &listName, DspMakefileGenerator *config);
+ QString configName(DspMakefileGenerator * config);
+
+ bool writeMakefile(QTextStream &);
+ bool writeProjectMakefile();
+ void writeSubDirs(QTextStream &t);
+ void init();
+
+public:
+ DspMakefileGenerator();
+ ~DspMakefileGenerator();
+
+ bool openOutput(QFile &file, const QString &build) const;
+ bool hasBuiltinCompiler(const QString &filename) const;
+
+protected:
+ virtual bool doDepends() const { return false; } //never necesary
+ virtual void processSources() { filterIncludedFiles("SOURCES"); filterIncludedFiles("GENERATED_SOURCES"); }
+ virtual QString replaceExtraCompilerVariables(const QString &, const QStringList &, const QStringList &);
+ inline QString replaceExtraCompilerVariables(const QString &val, const QString &in, const QString &out)
+ { return MakefileGenerator::replaceExtraCompilerVariables(val, in, out); }
+ virtual bool supportsMetaBuild() { return true; }
+ virtual bool supportsMergedBuilds() { return true; }
+ virtual bool mergeBuildProject(MakefileGenerator *other);
+ virtual void processPrlVariable(const QString &, const QStringList &);
+ virtual bool findLibraries();
+
+ bool usePCH;
+ QString precompH, namePCH,
+ precompObj, precompPch;
+
+ QString platform;
+
+ struct BuildStep {
+ BuildStep() {}
+ BuildStep &operator<<(const BuildStep &other) {
+ deps << other.deps;
+ buildStep += other.buildStep;
+ buildName += other.buildName;
+ buildOutputs += other.buildOutputs;
+ return *this;
+ }
+
+ QStringList deps;
+ QString buildStep;
+ QString buildName;
+ QStringList buildOutputs;
+ };
+ QMap<QString, BuildStep> swappedBuildSteps;
+
+ // Holds all configurations for glue (merged) project
+ QList<DspMakefileGenerator*> mergedProjects;
+};
+
+inline DspMakefileGenerator::~DspMakefileGenerator()
+{ }
+
+inline bool DspMakefileGenerator::findLibraries()
+{ return Win32MakefileGenerator::findLibraries("MSVCDSP_LIBS"); }
+
+QT_END_NAMESPACE
+
+#endif // MSVC_DSP_H
diff --git a/qmake/generators/win32/msvc_nmake.cpp b/qmake/generators/win32/msvc_nmake.cpp
new file mode 100644
index 0000000..4b1b66d
--- /dev/null
+++ b/qmake/generators/win32/msvc_nmake.cpp
@@ -0,0 +1,322 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "msvc_nmake.h"
+#include "option.h"
+#include <qregexp.h>
+#include <qhash.h>
+#include <qdir.h>
+#include <time.h>
+
+QT_BEGIN_NAMESPACE
+
+NmakeMakefileGenerator::NmakeMakefileGenerator() : Win32MakefileGenerator(), init_flag(false)
+{
+
+}
+
+bool
+NmakeMakefileGenerator::writeMakefile(QTextStream &t)
+{
+ writeHeader(t);
+ if(!project->values("QMAKE_FAILED_REQUIREMENTS").isEmpty()) {
+ QStringList &qut = project->values("QMAKE_EXTRA_TARGETS");
+ for(QStringList::ConstIterator it = qut.begin(); it != qut.end(); ++it)
+ t << *it << " ";
+ t << "all first clean:" << "\n\t"
+ << "@echo \"Some of the required modules ("
+ << var("QMAKE_FAILED_REQUIREMENTS") << ") are not available.\"" << "\n\t"
+ << "@echo \"Skipped.\"" << endl << endl;
+ writeMakeQmake(t);
+ return true;
+ }
+
+ if(project->first("TEMPLATE") == "app" ||
+ project->first("TEMPLATE") == "lib") {
+#if 0
+ if(Option::mkfile::do_stub_makefile)
+ return MakefileGenerator::writeStubMakefile(t);
+#endif
+ writeNmakeParts(t);
+ return MakefileGenerator::writeMakefile(t);
+ }
+ else if(project->first("TEMPLATE") == "subdirs") {
+ writeSubDirs(t);
+ return true;
+ }
+ return false;
+}
+
+QStringList &NmakeMakefileGenerator::findDependencies(const QString &file)
+{
+ QStringList &aList = MakefileGenerator::findDependencies(file);
+ // Note: The QMAKE_IMAGE_COLLECTION file have all images
+ // as dependency, so don't add precompiled header then
+ if (file == project->first("QMAKE_IMAGE_COLLECTION"))
+ return aList;
+ for(QStringList::Iterator it = Option::cpp_ext.begin(); it != Option::cpp_ext.end(); ++it) {
+ if(file.endsWith(*it)) {
+ if(!precompObj.isEmpty() && !aList.contains(precompObj))
+ aList += precompObj;
+ break;
+ }
+ }
+ return aList;
+}
+
+void NmakeMakefileGenerator::writeNmakeParts(QTextStream &t)
+{
+ writeStandardParts(t);
+
+ // precompiled header
+ if(usePCH) {
+ QString precompRule = QString("-c -Yc -Fp%1 -Fo%2").arg(precompPch).arg(precompObj);
+ t << precompObj << ": " << precompH << " " << findDependencies(precompH).join(" \\\n\t\t")
+ << "\n\t" << "$(CXX) " + precompRule +" $(CXXFLAGS) $(INCPATH) -TP " << precompH << endl << endl;
+ }
+}
+
+QString NmakeMakefileGenerator::var(const QString &value)
+{
+ if (usePCH) {
+ if ((value == "QMAKE_RUN_CXX_IMP_BATCH"
+ || value == "QMAKE_RUN_CXX_IMP"
+ || value == "QMAKE_RUN_CXX")) {
+ QFileInfo precompHInfo(fileInfo(precompH));
+ QString precompRule = QString("-c -FI%1 -Yu%2 -Fp%3")
+ .arg(precompHInfo.fileName())
+ .arg(precompHInfo.fileName())
+ .arg(precompPch);
+ QString p = MakefileGenerator::var(value);
+ p.replace("-c", precompRule);
+ // Cannot use -Gm with -FI & -Yu, as this gives an
+ // internal compiler error, on the newer compilers
+ p.remove("-Gm");
+ return p;
+ } else if (value == "QMAKE_CXXFLAGS") {
+ // Remove internal compiler error option
+ return MakefileGenerator::var(value).remove("-Gm");
+ }
+ }
+
+ // Normal val
+ return MakefileGenerator::var(value);
+}
+
+void NmakeMakefileGenerator::init()
+{
+ if(init_flag)
+ return;
+ init_flag = true;
+
+ /* this should probably not be here, but I'm using it to wrap the .t files */
+ if(project->first("TEMPLATE") == "app")
+ project->values("QMAKE_APP_FLAG").append("1");
+ else if(project->first("TEMPLATE") == "lib")
+ project->values("QMAKE_LIB_FLAG").append("1");
+ else if(project->first("TEMPLATE") == "subdirs") {
+ MakefileGenerator::init();
+ if(project->values("MAKEFILE").isEmpty())
+ project->values("MAKEFILE").append("Makefile");
+ if(project->values("QMAKE_QMAKE").isEmpty())
+ project->values("QMAKE_QMAKE").append("qmake");
+ if(project->isEmpty("QMAKE_COPY_FILE"))
+ project->values("QMAKE_COPY_FILE").append("$(COPY)");
+ if(project->isEmpty("QMAKE_COPY_DIR"))
+ project->values("QMAKE_COPY_DIR").append("xcopy /s /q /y /i");
+ if(project->isEmpty("QMAKE_INSTALL_FILE"))
+ project->values("QMAKE_INSTALL_FILE").append("$(COPY_FILE)");
+ if(project->isEmpty("QMAKE_INSTALL_PROGRAM"))
+ project->values("QMAKE_INSTALL_PROGRAM").append("$(COPY_FILE)");
+ if(project->isEmpty("QMAKE_INSTALL_DIR"))
+ project->values("QMAKE_INSTALL_DIR").append("$(COPY_DIR)");
+ return;
+ }
+
+ project->values("QMAKE_LIBS") += escapeFilePaths(project->values("LIBS"));
+ processVars();
+
+ if (!project->values("RES_FILE").isEmpty()) {
+ project->values("QMAKE_LIBS") += escapeFilePaths(project->values("RES_FILE"));
+ }
+
+ if(!project->values("DEF_FILE").isEmpty())
+ project->values("QMAKE_LFLAGS").append(QString("/DEF:") + escapeFilePath(project->first("DEF_FILE")));
+
+ if(!project->values("VERSION").isEmpty()) {
+ QString version = project->values("VERSION")[0];
+ int firstDot = version.indexOf(".");
+ QString major = version.left(firstDot);
+ QString minor = version.right(version.length() - firstDot - 1);
+ minor.replace(".", "");
+ project->values("QMAKE_LFLAGS").append("/VERSION:" + major + "." + minor);
+ }
+
+ // Base class init!
+ MakefileGenerator::init();
+
+ // Setup PCH variables
+ precompH = project->first("PRECOMPILED_HEADER");
+ usePCH = !precompH.isEmpty() && project->isActiveConfig("precompile_header");
+ if (usePCH) {
+ // Created files
+ precompObj = var("PRECOMPILED_DIR") + project->first("TARGET") + "_pch" + Option::obj_ext;
+ precompPch = var("PRECOMPILED_DIR") + project->first("TARGET") + "_pch.pch";
+ // Add linking of precompObj (required for whole precompiled classes)
+ project->values("OBJECTS") += precompObj;
+ // Add pch file to cleanup
+ project->values("QMAKE_CLEAN") += precompPch;
+ // Return to variable pool
+ project->values("PRECOMPILED_OBJECT") = QStringList(precompObj);
+ project->values("PRECOMPILED_PCH") = QStringList(precompPch);
+ }
+
+ QString version = project->first("TARGET_VERSION_EXT");
+ if(project->isActiveConfig("shared")) {
+ project->values("QMAKE_CLEAN").append(project->first("DESTDIR") + project->first("TARGET") + version + ".exp");
+ }
+ if(project->isActiveConfig("debug")) {
+ project->values("QMAKE_CLEAN").append(project->first("DESTDIR") + project->first("TARGET") + version + ".pdb");
+ project->values("QMAKE_CLEAN").append(project->first("DESTDIR") + project->first("TARGET") + version + ".ilk");
+ project->values("QMAKE_CLEAN").append("vc*.pdb");
+ project->values("QMAKE_CLEAN").append("vc*.idb");
+ }
+}
+
+void NmakeMakefileGenerator::writeLibDirPart(QTextStream &t)
+{
+ QStringList libDirs = project->values("QMAKE_LIBDIR");
+ for (int i = 0; i < libDirs.size(); ++i)
+ libDirs[i].remove("\"");
+ t << valGlue(libDirs,"/LIBPATH:\"","\" /LIBPATH:\"","\"") << " ";
+}
+
+void NmakeMakefileGenerator::writeImplicitRulesPart(QTextStream &t)
+{
+ t << ".SUFFIXES:";
+ for(QStringList::Iterator cit = Option::c_ext.begin(); cit != Option::c_ext.end(); ++cit)
+ t << " " << (*cit);
+ for(QStringList::Iterator cppit = Option::cpp_ext.begin(); cppit != Option::cpp_ext.end(); ++cppit)
+ t << " " << (*cppit);
+ t << endl << endl;
+
+ if(!project->isActiveConfig("no_batch")) {
+ // Batchmode doesn't use the non implicit rules QMAKE_RUN_CXX & QMAKE_RUN_CC
+ project->variables().remove("QMAKE_RUN_CXX");
+ project->variables().remove("QMAKE_RUN_CC");
+
+ QHash<QString, void*> source_directories;
+ source_directories.insertMulti(".", (void*)1);
+ QString directories[] = { QString("UI_SOURCES_DIR"), QString("UI_DIR"), QString() };
+ for(int y = 0; !directories[y].isNull(); y++) {
+ QString dirTemp = project->first(directories[y]);
+ if (dirTemp.endsWith("\\"))
+ dirTemp.truncate(dirTemp.length()-1);
+ if(!dirTemp.isEmpty())
+ source_directories.insertMulti(dirTemp, (void*)1);
+ }
+ QString srcs[] = { QString("SOURCES"), QString("GENERATED_SOURCES"), QString() };
+ for(int x = 0; !srcs[x].isNull(); x++) {
+ QStringList &l = project->values(srcs[x]);
+ for(QStringList::Iterator sit = l.begin(); sit != l.end(); ++sit) {
+ QString sep = "\\";
+ if((*sit).indexOf(sep) == -1)
+ sep = "/";
+ QString dir = (*sit).section(sep, 0, -2);
+ if(!dir.isEmpty() && !source_directories[dir])
+ source_directories.insertMulti(dir, (void*)1);
+ }
+ }
+
+ for(QHash<QString, void*>::Iterator it(source_directories.begin()); it != source_directories.end(); ++it) {
+ if(it.key().isEmpty())
+ continue;
+ QString objDir = var("OBJECTS_DIR");
+ if (objDir == ".\\")
+ objDir = "";
+ for(QStringList::Iterator cppit = Option::cpp_ext.begin(); cppit != Option::cpp_ext.end(); ++cppit)
+ t << "{" << it.key() << "}" << (*cppit) << "{" << objDir << "}" << Option::obj_ext << "::\n\t"
+ << var("QMAKE_RUN_CXX_IMP_BATCH").replace(QRegExp("\\$@"), var("OBJECTS_DIR")) << endl << "\t$<" << endl << "<<" << endl << endl;
+ for(QStringList::Iterator cit = Option::c_ext.begin(); cit != Option::c_ext.end(); ++cit)
+ t << "{" << it.key() << "}" << (*cit) << "{" << objDir << "}" << Option::obj_ext << "::\n\t"
+ << var("QMAKE_RUN_CC_IMP_BATCH").replace(QRegExp("\\$@"), var("OBJECTS_DIR")) << endl << "\t$<" << endl << "<<" << endl << endl;
+ }
+ } else {
+ for(QStringList::Iterator cppit = Option::cpp_ext.begin(); cppit != Option::cpp_ext.end(); ++cppit)
+ t << (*cppit) << Option::obj_ext << ":\n\t" << var("QMAKE_RUN_CXX_IMP") << endl << endl;
+ for(QStringList::Iterator cit = Option::c_ext.begin(); cit != Option::c_ext.end(); ++cit)
+ t << (*cit) << Option::obj_ext << ":\n\t" << var("QMAKE_RUN_CC_IMP") << endl << endl;
+ }
+
+}
+
+void NmakeMakefileGenerator::writeBuildRulesPart(QTextStream &t)
+{
+ t << "first: all" << endl;
+ t << "all: " << fileFixify(Option::output.fileName()) << " " << varGlue("ALL_DEPS"," "," "," ") << "$(DESTDIR_TARGET)" << endl << endl;
+ t << "$(DESTDIR_TARGET): " << var("PRE_TARGETDEPS") << " $(OBJECTS) " << var("POST_TARGETDEPS");
+
+ if(!project->isEmpty("QMAKE_PRE_LINK"))
+ t << "\n\t" <<var("QMAKE_PRE_LINK");
+ if(project->isActiveConfig("staticlib")) {
+ t << "\n\t" << "$(LIBAPP) $(LIBFLAGS) /OUT:$(DESTDIR_TARGET) @<<" << "\n\t "
+ << "$(OBJECTS)";
+ } else {
+ t << "\n\t" << "$(LINK) $(LFLAGS) /OUT:$(DESTDIR_TARGET) @<< " << "\n\t "
+ << "$(OBJECTS) $(LIBS)";
+ }
+ t << endl << "<<";
+ QString signature = !project->isEmpty("SIGNATURE_FILE") ? var("SIGNATURE_FILE") : var("DEFAULT_SIGNATURE");
+ bool useSignature = !signature.isEmpty() && !project->isActiveConfig("staticlib") &&
+ !project->isEmpty("CE_SDK") && !project->isEmpty("CE_ARCH");
+ if(useSignature) {
+ t << "\n\tsigntool sign /F " << signature << " $(DESTDIR_TARGET)";
+ }
+ if(!project->isEmpty("QMAKE_POST_LINK")) {
+ if (useSignature)
+ t << " && " << var("QMAKE_POST_LINK");
+ else
+ t << "\n\t" << var("QMAKE_POST_LINK");
+ }
+ t << endl;
+}
+
+QT_END_NAMESPACE
diff --git a/qmake/generators/win32/msvc_nmake.h b/qmake/generators/win32/msvc_nmake.h
new file mode 100644
index 0000000..f4e8de6
--- /dev/null
+++ b/qmake/generators/win32/msvc_nmake.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef MSVC_NMAKE_H
+#define MSVC_NMAKE_H
+
+#include "winmakefile.h"
+
+QT_BEGIN_NAMESPACE
+
+class NmakeMakefileGenerator : public Win32MakefileGenerator
+{
+ bool init_flag;
+ void writeNmakeParts(QTextStream &);
+ void writeLibDirPart(QTextStream &t);
+ bool writeMakefile(QTextStream &);
+ void writeImplicitRulesPart(QTextStream &t);
+ void writeBuildRulesPart(QTextStream &t);
+ void init();
+
+protected:
+ virtual QStringList &findDependencies(const QString &file);
+ QString var(const QString &value);
+ QString precompH, precompObj, precompPch;
+ bool usePCH;
+
+public:
+ NmakeMakefileGenerator();
+ ~NmakeMakefileGenerator();
+
+};
+
+inline NmakeMakefileGenerator::~NmakeMakefileGenerator()
+{ }
+
+QT_END_NAMESPACE
+
+#endif // MSVC_NMAKE_H
diff --git a/qmake/generators/win32/msvc_objectmodel.cpp b/qmake/generators/win32/msvc_objectmodel.cpp
new file mode 100644
index 0000000..c1f5ce1
--- /dev/null
+++ b/qmake/generators/win32/msvc_objectmodel.cpp
@@ -0,0 +1,2636 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "msvc_objectmodel.h"
+#include "msvc_vcproj.h"
+#include <qstringlist.h>
+#include <qfileinfo.h>
+
+QT_BEGIN_NAMESPACE
+
+// XML Tags ---------------------------------------------------------
+const char _Configuration[] = "Configuration";
+const char _Configurations[] = "Configurations";
+const char _File[] = "File";
+const char _FileConfiguration[] = "FileConfiguration";
+const char _Files[] = "Files";
+const char _Filter[] = "Filter";
+const char _Globals[] = "Globals";
+const char _Platform[] = "Platform";
+const char _Platforms[] = "Platforms";
+const char _Tool[] = "Tool";
+const char _VisualStudioProject[] = "VisualStudioProject";
+
+// XML Properties ---------------------------------------------------
+const char _AddModuleNamesToAssembly[] = "AddModuleNamesToAssembly";
+const char _AdditionalDependencies[] = "AdditionalDependencies";
+const char _AdditionalFiles[] = "AdditionalFiles";
+const char _AdditionalIncludeDirectories[] = "AdditionalIncludeDirectories";
+const char _AdditionalLibraryDirectories[] = "AdditionalLibraryDirectories";
+const char _AdditionalOptions[] = "AdditionalOptions";
+const char _AdditionalUsingDirectories[] = "AdditionalUsingDirectories";
+const char _AssemblerListingLocation[] = "AssemblerListingLocation";
+const char _AssemblerOutput[] = "AssemblerOutput";
+const char _ATLMinimizesCRunTimeLibraryUsage[] = "ATLMinimizesCRunTimeLibraryUsage";
+const char _BaseAddress[] = "BaseAddress";
+const char _BasicRuntimeChecks[] = "BasicRuntimeChecks";
+const char _BrowseInformation[] = "BrowseInformation";
+const char _BrowseInformationFile[] = "BrowseInformationFile";
+const char _BufferSecurityCheck[] = "BufferSecurityCheck";
+const char _BuildBrowserInformation[] = "BuildBrowserInformation";
+const char _CPreprocessOptions[] = "CPreprocessOptions";
+const char _CallingConvention[] = "CallingConvention";
+const char _CharacterSet[] = "CharacterSet";
+const char _CommandLine[] = "CommandLine";
+const char _CompileAs[] = "CompileAs";
+const char _CompileAsManaged[] = "CompileAsManaged";
+const char _CompileOnly[] = "CompileOnly";
+const char _ConfigurationType[] = "ConfigurationType";
+const char _Culture[] = "Culture";
+const char _DLLDataFileName[] = "DLLDataFileName";
+const char _DebugInformationFormat[] = "DebugInformationFormat";
+const char _DefaultCharIsUnsigned[] = "DefaultCharIsUnsigned";
+const char _DefaultCharType[] = "DefaultCharType";
+const char _DelayLoadDLLs[] = "DelayLoadDLLs";
+const char _DeleteExtensionsOnClean[] = "DeleteExtensionsOnClean";
+const char _Description[] = "Description";
+const char _Detect64BitPortabilityProblems[] = "Detect64BitPortabilityProblems";
+const char _DisableLanguageExtensions[] = "DisableLanguageExtensions";
+const char _DisableSpecificWarnings[] = "DisableSpecificWarnings";
+const char _EnableCOMDATFolding[] = "EnableCOMDATFolding";
+const char _EnableErrorChecks[] = "EnableErrorChecks";
+const char _EnableEnhancedInstructionSet[] = "EnableEnhancedInstructionSet";
+const char _EnableFiberSafeOptimizations[] = "EnableFiberSafeOptimizations";
+const char _EnableFunctionLevelLinking[] = "EnableFunctionLevelLinking";
+const char _EnableIntrinsicFunctions[] = "EnableIntrinsicFunctions";
+const char _EntryPointSymbol[] = "EntryPointSymbol";
+const char _ErrorCheckAllocations[] = "ErrorCheckAllocations";
+const char _ErrorCheckBounds[] = "ErrorCheckBounds";
+const char _ErrorCheckEnumRange[] = "ErrorCheckEnumRange";
+const char _ErrorCheckRefPointers[] = "ErrorCheckRefPointers";
+const char _ErrorCheckStubData[] = "ErrorCheckStubData";
+const char _ExceptionHandling[] = "ExceptionHandling";
+const char _ExcludedFromBuild[] = "ExcludedFromBuild";
+const char _ExpandAttributedSource[] = "ExpandAttributedSource";
+const char _ExportNamedFunctions[] = "ExportNamedFunctions";
+const char _FavorSizeOrSpeed[] = "FavorSizeOrSpeed";
+const char _FloatingPointModel[] = "FloatingPointModel";
+const char _FloatingPointExceptions[] = "FloatingPointExceptions";
+const char _ForceConformanceInForLoopScope[] = "ForceConformanceInForLoopScope";
+const char _ForceSymbolReferences[] = "ForceSymbolReferences";
+const char _ForcedIncludeFiles[] = "ForcedIncludeFiles";
+const char _ForcedUsingFiles[] = "ForcedUsingFiles";
+const char _FullIncludePath[] = "FullIncludePath";
+const char _FunctionOrder[] = "FunctionOrder";
+const char _GenerateDebugInformation[] = "GenerateDebugInformation";
+const char _GenerateMapFile[] = "GenerateMapFile";
+const char _GeneratePreprocessedFile[] = "GeneratePreprocessedFile";
+const char _GenerateStublessProxies[] = "GenerateStublessProxies";
+const char _GenerateTypeLibrary[] = "GenerateTypeLibrary";
+const char _GlobalOptimizations[] = "GlobalOptimizations";
+const char _HeaderFileName[] = "HeaderFileName";
+const char _HeapCommitSize[] = "HeapCommitSize";
+const char _HeapReserveSize[] = "HeapReserveSize";
+const char _IgnoreAllDefaultLibraries[] = "IgnoreAllDefaultLibraries";
+const char _IgnoreDefaultLibraryNames[] = "IgnoreDefaultLibraryNames";
+const char _IgnoreEmbeddedIDL[] = "IgnoreEmbeddedIDL";
+const char _IgnoreImportLibrary[] = "IgnoreImportLibrary";
+const char _IgnoreStandardIncludePath[] = "IgnoreStandardIncludePath";
+const char _ImportLibrary[] = "ImportLibrary";
+const char _ImproveFloatingPointConsistency[] = "ImproveFloatingPointConsistency";
+const char _InlineFunctionExpansion[] = "InlineFunctionExpansion";
+const char _InterfaceIdentifierFileName[] = "InterfaceIdentifierFileName";
+const char _IntermediateDirectory[] = "IntermediateDirectory";
+const char _KeepComments[] = "KeepComments";
+const char _LargeAddressAware[] = "LargeAddressAware";
+const char _LinkDLL[] = "LinkDLL";
+const char _LinkIncremental[] = "LinkIncremental";
+const char _LinkTimeCodeGeneration[] = "LinkTimeCodeGeneration";
+const char _LinkToManagedResourceFile[] = "LinkToManagedResourceFile";
+const char _MapExports[] = "MapExports";
+const char _MapFileName[] = "MapFileName";
+const char _MapLines[] = "MapLines ";
+const char _MergeSections[] = "MergeSections";
+const char _MergedIDLBaseFileName[] = "MergedIDLBaseFileName";
+const char _MidlCommandFile[] = "MidlCommandFile";
+const char _MinimalRebuild[] = "MinimalRebuild";
+const char _MkTypLibCompatible[] = "MkTypLibCompatible";
+const char _ModuleDefinitionFile[] = "ModuleDefinitionFile";
+const char _Name[] = "Name";
+const char _ObjectFile[] = "ObjectFile";
+const char _OmitFramePointers[] = "OmitFramePointers";
+const char _OpenMP[] = "OpenMP";
+const char _Optimization[] = "Optimization ";
+const char _OptimizeForProcessor[] = "OptimizeForProcessor";
+const char _OptimizeForWindows98[] = "OptimizeForWindows98";
+const char _OptimizeForWindowsApplication[] = "OptimizeForWindowsApplication";
+const char _OptimizeReferences[] = "OptimizeReferences";
+const char _OutputDirectory[] = "OutputDirectory";
+const char _OutputFile[] = "OutputFile";
+const char _Outputs[] = "Outputs";
+const char _ParseFiles[] = "ParseFiles";
+const char _PrecompiledHeaderFile[] = "PrecompiledHeaderFile";
+const char _PrecompiledHeaderThrough[] = "PrecompiledHeaderThrough";
+const char _PreprocessorDefinitions[] = "PreprocessorDefinitions";
+const char _PrimaryOutput[] = "PrimaryOutput";
+const char _ProjectGUID[] = "ProjectGUID";
+const char _Keyword[] = "Keyword";
+const char _ProjectType[] = "ProjectType";
+const char _ProgramDatabase[] = "ProgramDatabase";
+const char _ProgramDataBaseFileName[] = "ProgramDataBaseFileName";
+const char _ProgramDatabaseFile[] = "ProgramDatabaseFile";
+const char _ProxyFileName[] = "ProxyFileName";
+const char _RedirectOutputAndErrors[] = "RedirectOutputAndErrors";
+const char _RegisterOutput[] = "RegisterOutput";
+const char _RelativePath[] = "RelativePath";
+const char _RemoteDirectory[] = "RemoteDirectory";
+const char _ResourceOnlyDLL[] = "ResourceOnlyDLL";
+const char _ResourceOutputFileName[] = "ResourceOutputFileName";
+const char _RuntimeLibrary[] = "RuntimeLibrary";
+const char _RuntimeTypeInfo[] = "RuntimeTypeInfo";
+const char _SccProjectName[] = "SccProjectName";
+const char _SccLocalPath[] = "SccLocalPath";
+const char _SetChecksum[] = "SetChecksum";
+const char _ShowIncludes[] = "ShowIncludes";
+const char _ShowProgress[] = "ShowProgress";
+const char _SmallerTypeCheck[] = "SmallerTypeCheck";
+const char _StackCommitSize[] = "StackCommitSize";
+const char _StackReserveSize[] = "StackReserveSize";
+const char _StringPooling[] = "StringPooling";
+const char _StripPrivateSymbols[] = "StripPrivateSymbols";
+const char _StructMemberAlignment[] = "StructMemberAlignment";
+const char _SubSystem[] = "SubSystem";
+const char _SupportUnloadOfDelayLoadedDLL[] = "SupportUnloadOfDelayLoadedDLL";
+const char _SuppressStartupBanner[] = "SuppressStartupBanner";
+const char _SwapRunFromCD[] = "SwapRunFromCD";
+const char _SwapRunFromNet[] = "SwapRunFromNet";
+const char _TargetEnvironment[] = "TargetEnvironment";
+const char _TargetMachine[] = "TargetMachine";
+const char _TerminalServerAware[] = "TerminalServerAware";
+const char _Path[] = "Path";
+const char _TreatWChar_tAsBuiltInType[] = "TreatWChar_tAsBuiltInType";
+const char _TurnOffAssemblyGeneration[] = "TurnOffAssemblyGeneration";
+const char _TypeLibraryFile[] = "TypeLibraryFile";
+const char _TypeLibraryName[] = "TypeLibraryName";
+const char _TypeLibraryResourceID[] = "TypeLibraryResourceID";
+const char _UndefineAllPreprocessorDefinitions[]= "UndefineAllPreprocessorDefinitions";
+const char _UndefinePreprocessorDefinitions[] = "UndefinePreprocessorDefinitions";
+const char _UniqueIdentifier[] = "UniqueIdentifier";
+const char _UseOfATL[] = "UseOfATL";
+const char _UseOfMfc[] = "UseOfMfc";
+const char _UsePrecompiledHeader[] = "UsePrecompiledHeader";
+const char _ValidateParameters[] = "ValidateParameters";
+const char _VCCLCompilerTool[] = "VCCLCompilerTool";
+const char _VCLibrarianTool[] = "VCLibrarianTool";
+const char _VCLinkerTool[] = "VCLinkerTool";
+const char _VCCustomBuildTool[] = "VCCustomBuildTool";
+const char _VCResourceCompilerTool[] = "VCResourceCompilerTool";
+const char _VCMIDLTool[] = "VCMIDLTool";
+const char _Version[] = "Version";
+const char _WarnAsError[] = "WarnAsError";
+const char _WarningLevel[] = "WarningLevel";
+const char _WholeProgramOptimization[] = "WholeProgramOptimization";
+const char _CompileForArchitecture[] = "CompileForArchitecture";
+const char _InterworkCalls[] = "InterworkCalls";
+
+// XmlOutput stream functions ------------------------------
+inline XmlOutput::xml_output attrT(const char *name, const triState v)
+{
+ if(v == unset)
+ return noxml();
+ return attr(name, (v == _True ? "true" : "false"));
+}
+
+inline XmlOutput::xml_output attrE(const char *name, int v)
+{
+ return attr(name, QString::number(v));
+}
+
+/*ifNot version*/
+inline XmlOutput::xml_output attrE(const char *name, int v, int ifn)
+{
+ if (v == ifn)
+ return noxml();
+ return attr(name, QString::number(v));
+}
+
+inline XmlOutput::xml_output attrL(const char *name, qint64 v)
+{
+ return attr(name, QString::number(v));
+}
+
+/*ifNot version*/
+inline XmlOutput::xml_output attrL(const char *name, qint64 v, qint64 ifn)
+{
+ if (v == ifn)
+ return noxml();
+ return attr(name, QString::number(v));
+}
+
+inline XmlOutput::xml_output attrS(const char *name, const QString &v)
+{
+ if(v.isEmpty())
+ return noxml();
+ return attr(name, v);
+}
+
+inline XmlOutput::xml_output attrX(const char *name, const QStringList &v, const char *s = ",")
+{
+ if(v.isEmpty())
+ return noxml();
+ return attr(name, v.join(s));
+}
+
+// VCCLCompilerTool -------------------------------------------------
+VCCLCompilerTool::VCCLCompilerTool()
+ : AssemblerOutput(asmListingNone),
+ BasicRuntimeChecks(runtimeBasicCheckNone),
+ BrowseInformation(brInfoNone),
+ BufferSecurityCheck(_False),
+ CallingConvention(callConventionDefault),
+ CompileAs(compileAsDefault),
+ CompileAsManaged(managedDefault),
+ CompileOnly(unset),
+ DebugInformationFormat(debugDisabled),
+ DefaultCharIsUnsigned(unset),
+ Detect64BitPortabilityProblems(unset),
+ DisableLanguageExtensions(unset),
+ EnableEnhancedInstructionSet(archNotSet),
+ EnableFiberSafeOptimizations(unset),
+ EnableFunctionLevelLinking(unset),
+ EnableIntrinsicFunctions(unset),
+ ExceptionHandling(ehDefault),
+ ExpandAttributedSource(unset),
+ FavorSizeOrSpeed(favorNone),
+ FloatingPointModel(floatingPointNotSet),
+ FloatingPointExceptions(unset),
+ ForceConformanceInForLoopScope(unset),
+ GeneratePreprocessedFile(preprocessNo),
+ GlobalOptimizations(unset),
+ IgnoreStandardIncludePath(unset),
+ ImproveFloatingPointConsistency(unset),
+ InlineFunctionExpansion(expandDefault),
+ KeepComments(unset),
+ MinimalRebuild(unset),
+ OmitFramePointers(unset),
+ OpenMP(unset),
+ Optimization(optimizeCustom),
+ OptimizeForProcessor(procOptimizeBlended),
+ OptimizeForWindowsApplication(unset),
+ ProgramDataBaseFileName(""),
+ RuntimeLibrary(rtMultiThreaded),
+ RuntimeTypeInfo(unset),
+ ShowIncludes(unset),
+ SmallerTypeCheck(unset),
+ StringPooling(unset),
+ StructMemberAlignment(alignNotSet),
+ SuppressStartupBanner(unset),
+ TreatWChar_tAsBuiltInType(unset),
+ TurnOffAssemblyGeneration(unset),
+ UndefineAllPreprocessorDefinitions(unset),
+ UsePrecompiledHeader(pchNone),
+ WarnAsError(unset),
+ WarningLevel(warningLevel_0),
+ WholeProgramOptimization(unset),
+ CompileForArchitecture(archUnknown),
+ InterworkCalls(unset)
+{
+}
+
+/*
+ * Some values for the attribute UsePrecompiledHeader have changed from VS 2003 to VS 2005,
+ * see the following chart, so we need a function that transforms those values if we are
+ * using NET2005:
+ *
+ * Meaning 2003 2005
+ * -----------------------------------------
+ * Don't use PCH 0 0
+ * Create PCH (/Yc) 1 1
+ * Automatically generate (/YX) 2 (seems that it was removed)
+ * Use specific PCH (/Yu) 3 2
+ *
+ */
+inline XmlOutput::xml_output xformUsePrecompiledHeaderForNET2005(pchOption whatPch, DotNET compilerVersion)
+{
+ if (compilerVersion >= NET2005) {
+ if (whatPch == pchGenerateAuto) whatPch = (pchOption)0;
+ if (whatPch == pchUseUsingSpecific) whatPch = (pchOption)2;
+ }
+ return attrE(_UsePrecompiledHeader, whatPch);
+}
+
+inline XmlOutput::xml_output xformExceptionHandlingNET2005(exceptionHandling eh, DotNET compilerVersion)
+{
+ if (eh == ehDefault)
+ return noxml();
+
+ if (compilerVersion >= NET2005)
+ return attrE(_ExceptionHandling, eh);
+
+ return attrS(_ExceptionHandling, (eh == ehNoSEH ? "true" : "false"));
+}
+
+XmlOutput &operator<<(XmlOutput &xml, const VCCLCompilerTool &tool)
+{
+ return xml
+ << tag(_Tool)
+ << attrS(_Name, _VCCLCompilerTool)
+ << attrX(_AdditionalIncludeDirectories, tool.AdditionalIncludeDirectories)
+ << attrX(_AdditionalOptions, tool.AdditionalOptions, " ")
+ << attrX(_AdditionalUsingDirectories, tool.AdditionalUsingDirectories)
+ << attrS(_AssemblerListingLocation, tool.AssemblerListingLocation)
+ << attrE(_AssemblerOutput, tool.AssemblerOutput, /*ifNot*/ asmListingNone)
+ << attrE(_BasicRuntimeChecks, tool.BasicRuntimeChecks, /*ifNot*/ runtimeBasicCheckNone)
+ << attrE(_BrowseInformation, tool.BrowseInformation, /*ifNot*/ brInfoNone)
+ << attrS(_BrowseInformationFile, tool.BrowseInformationFile)
+ << attrT(_BufferSecurityCheck, tool.BufferSecurityCheck)
+ << attrE(_CallingConvention, tool.CallingConvention, /*ifNot*/ callConventionDefault)
+ << attrE(_CompileAs, tool.CompileAs, compileAsDefault)
+ << attrE(_CompileAsManaged, tool.CompileAsManaged, /*ifNot*/ managedDefault)
+ << attrT(_CompileOnly, tool.CompileOnly)
+ << attrE(_DebugInformationFormat, tool.DebugInformationFormat, /*ifNot*/ debugUnknown)
+ << attrT(_DefaultCharIsUnsigned, tool.DefaultCharIsUnsigned)
+ << attrT(_Detect64BitPortabilityProblems, tool.Detect64BitPortabilityProblems)
+ << attrT(_DisableLanguageExtensions, tool.DisableLanguageExtensions)
+ << attrX(_DisableSpecificWarnings, tool.DisableSpecificWarnings)
+ << attrE(_EnableEnhancedInstructionSet, tool.EnableEnhancedInstructionSet, /*ifnot*/ archNotSet)
+ << attrT(_EnableFiberSafeOptimizations, tool.EnableFiberSafeOptimizations)
+ << attrT(_EnableFunctionLevelLinking, tool.EnableFunctionLevelLinking)
+ << attrT(_EnableIntrinsicFunctions, tool.EnableIntrinsicFunctions)
+ << xformExceptionHandlingNET2005(tool.ExceptionHandling, tool.config->CompilerVersion)
+ << attrT(_ExpandAttributedSource, tool.ExpandAttributedSource)
+ << attrE(_FavorSizeOrSpeed, tool.FavorSizeOrSpeed, /*ifNot*/ favorNone)
+
+ << attrE(_FloatingPointModel, tool.FloatingPointModel, /*ifNot*/ floatingPointNotSet)
+ << attrT(_FloatingPointExceptions, tool.FloatingPointExceptions)
+
+ << attrT(_ForceConformanceInForLoopScope, tool.ForceConformanceInForLoopScope)
+ << attrX(_ForcedIncludeFiles, tool.ForcedIncludeFiles)
+ << attrX(_ForcedUsingFiles, tool.ForcedUsingFiles)
+ << attrE(_GeneratePreprocessedFile, tool.GeneratePreprocessedFile, /*ifNot*/ preprocessUnknown)
+ << attrT(_GlobalOptimizations, tool.GlobalOptimizations)
+ << attrT(_IgnoreStandardIncludePath, tool.IgnoreStandardIncludePath)
+ << attrT(_ImproveFloatingPointConsistency, tool.ImproveFloatingPointConsistency)
+ << attrE(_InlineFunctionExpansion, tool.InlineFunctionExpansion, /*ifNot*/ expandDefault)
+ << attrT(_KeepComments, tool.KeepComments)
+ << attrT(_MinimalRebuild, tool.MinimalRebuild)
+ << attrS(_ObjectFile, tool.ObjectFile)
+ << attrT(_OmitFramePointers, tool.OmitFramePointers)
+ << attrT(_OpenMP, tool.OpenMP)
+ << attrE(_Optimization, tool.Optimization, /*ifNot*/ optimizeDefault)
+ << attrE(_OptimizeForProcessor, tool.OptimizeForProcessor, /*ifNot*/ procOptimizeBlended)
+ << attrT(_OptimizeForWindowsApplication, tool.OptimizeForWindowsApplication)
+ << attrS(_OutputFile, tool.OutputFile)
+ << attrS(_PrecompiledHeaderFile, tool.PrecompiledHeaderFile)
+ << attrS(_PrecompiledHeaderThrough, tool.PrecompiledHeaderThrough)
+ << attrX(_PreprocessorDefinitions, tool.PreprocessorDefinitions)
+ << (tool.ProgramDataBaseFileName.isNull() ? noxml() : attr(_ProgramDataBaseFileName, tool.ProgramDataBaseFileName))
+ << attrE(_RuntimeLibrary, tool.RuntimeLibrary, /*ifNot*/ rtUnknown)
+ << attrT(_RuntimeTypeInfo, tool.RuntimeTypeInfo)
+ << attrT(_ShowIncludes, tool.ShowIncludes)
+ << attrT(_SmallerTypeCheck, tool.SmallerTypeCheck)
+ << attrT(_StringPooling, tool.StringPooling)
+ << attrE(_StructMemberAlignment, tool.StructMemberAlignment, /*ifNot*/ alignNotSet)
+ << attrT(_SuppressStartupBanner, tool.SuppressStartupBanner)
+ << attrT(_TreatWChar_tAsBuiltInType, tool.TreatWChar_tAsBuiltInType)
+ << attrT(_TurnOffAssemblyGeneration, tool.TurnOffAssemblyGeneration)
+ << attrT(_UndefineAllPreprocessorDefinitions, tool.UndefineAllPreprocessorDefinitions)
+ << attrX(_UndefinePreprocessorDefinitions, tool.UndefinePreprocessorDefinitions)
+ << (!tool.PrecompiledHeaderFile.isEmpty() || !tool.PrecompiledHeaderThrough.isEmpty() ? xformUsePrecompiledHeaderForNET2005(tool.UsePrecompiledHeader, tool.config->CompilerVersion) : noxml())
+ << attrT(_WarnAsError, tool.WarnAsError)
+ << attrE(_WarningLevel, tool.WarningLevel, /*ifNot*/ warningLevelUnknown)
+ << attrT(_WholeProgramOptimization, tool.WholeProgramOptimization)
+ << attrE(_CompileForArchitecture, tool.CompileForArchitecture, /*ifNot*/ archUnknown)
+ << attrT(_InterworkCalls, tool.InterworkCalls)
+
+ << closetag(_Tool);
+}
+
+bool VCCLCompilerTool::parseOption(const char* option)
+{
+ // skip index 0 ('/' or '-')
+ char first = option[1];
+ char second = option[2];
+ char third = option[3];
+ char fourth = option[4];
+ bool found = true;
+
+ switch (first) {
+ case '?':
+ case 'h':
+ qWarning("Generator: Option '/?', '/help': MSVC.NET projects do not support outputting help info");
+ found = false;
+ break;
+ case '@':
+ qWarning("Generator: Option '/@': MSVC.NET projects do not support the use of a response file");
+ found = false;
+ break;
+ case 'l':
+ qWarning("Generator: Option '/link': qmake generator does not support passing link options through the compiler tool");
+ found = false;
+ break;
+ case 'A':
+ if(second != 'I') {
+ found = false; break;
+ }
+ AdditionalUsingDirectories += option+3;
+ break;
+ case 'C':
+ KeepComments = _True;
+ break;
+ case 'D':
+ PreprocessorDefinitions += option+2;
+ break;
+ case 'E':
+ if(second == 'H') {
+ QString opt(option);
+ if (opt.contains('a') && !opt.contains('s') && !opt.contains('c'))
+ ExceptionHandling = ehSEH;
+ else if (!opt.contains('a') && opt.contains("s-") && opt.contains("c-"))
+ ExceptionHandling = ehNone;
+ else if (!opt.contains('a') && opt.contains('s') && opt.contains('c'))
+ ExceptionHandling = ehNoSEH;
+ else {
+ // ExceptionHandling must be false, or it will override
+ // with an /EHsc option
+ ExceptionHandling = ehNone;
+ AdditionalOptions += option;
+ }
+ if (config->CompilerVersion < NET2005
+ && ExceptionHandling == ehSEH) {
+ ExceptionHandling = ehNone;
+ AdditionalOptions += option;
+ }
+ break;
+ }
+ GeneratePreprocessedFile = preprocessYes;
+ break;
+ case 'F':
+ if(second <= '9' && second >= '0') {
+ AdditionalOptions += option;
+ break;
+ } else {
+ switch (second) {
+ case 'A':
+ if(third == 'c') {
+ AssemblerOutput = asmListingAsmMachine;
+ if(fourth == 's')
+ AssemblerOutput = asmListingAsmMachineSrc;
+ } else if(third == 's') {
+ AssemblerOutput = asmListingAsmSrc;
+ } else {
+ AssemblerOutput = asmListingAssemblyOnly;
+ }
+ break;
+ case 'a':
+ AssemblerListingLocation = option+3;
+ break;
+ case 'I':
+ ForcedIncludeFiles += option+3;
+ break;
+ case 'R':
+ BrowseInformation = brAllInfo;
+ BrowseInformationFile = option+3;
+ break;
+ case 'r':
+ BrowseInformation = brNoLocalSymbols;
+ BrowseInformationFile = option+3;
+ break;
+ case 'U':
+ ForcedUsingFiles += option+3;
+ break;
+ case 'd':
+ ProgramDataBaseFileName = option+3;
+ break;
+ case 'e':
+ OutputFile = option+3;
+ break;
+ case 'm':
+ AdditionalOptions += option;
+ break;
+ case 'o':
+ ObjectFile = option+3;
+ break;
+ case 'p':
+ PrecompiledHeaderFile = option+3;
+ break;
+ case 'x':
+ ExpandAttributedSource = _True;
+ break;
+ default:
+ found = false; break;
+ }
+ }
+ break;
+ case 'G':
+ switch (second) {
+ case '3':
+ case '4':
+ qWarning("Option '/G3' and '/G4' were phased out in Visual C++ 5.0");
+ found = false; break;
+ case '5':
+ OptimizeForProcessor = procOptimizePentium;
+ break;
+ case '6':
+ case 'B':
+ OptimizeForProcessor = procOptimizePentiumProAndAbove;
+ break;
+ case '7':
+ OptimizeForProcessor = procOptimizePentium4AndAbove;
+ break;
+ case 'A':
+ OptimizeForWindowsApplication = _True;
+ break;
+ case 'F':
+ StringPooling = _True;
+ break;
+ case 'H':
+ AdditionalOptions += option;
+ break;
+ case 'L':
+ WholeProgramOptimization = _True;
+ if(third == '-')
+ WholeProgramOptimization = _False;
+ break;
+ case 'R':
+ RuntimeTypeInfo = _True;
+ if(third == '-')
+ RuntimeTypeInfo = _False;
+ break;
+ case 'S':
+ BufferSecurityCheck = _True;
+ break;
+ case 'T':
+ EnableFiberSafeOptimizations = _True;
+ break;
+ case 'X':
+ // Same as the /EHsc option, which is Exception Handling without SEH
+ ExceptionHandling = ehNoSEH;
+ if (third == '-')
+ ExceptionHandling = ehNone;
+ break;
+ case 'Z':
+ case 'e':
+ case 'h':
+ AdditionalOptions += option;
+ break;
+ case 'd':
+ CallingConvention = callConventionCDecl;
+ break;
+ case 'f':
+ StringPooling = _True;
+ AdditionalOptions += option;
+ break;
+ case 'm':
+ MinimalRebuild = _True;
+ if(third == '-')
+ MinimalRebuild = _False;
+ break;
+ case 'r':
+ CallingConvention = callConventionFastCall;
+ break;
+ case 's':
+ // Warning: following [num] is not used,
+ // were should we put it?
+ BufferSecurityCheck = _True;
+ break;
+ case 'y':
+ EnableFunctionLevelLinking = _True;
+ break;
+ case 'z':
+ CallingConvention = callConventionStdCall;
+ break;
+ default:
+ found = false; break;
+ }
+ break;
+ case 'H':
+ AdditionalOptions += option;
+ break;
+ case 'I':
+ AdditionalIncludeDirectories += option+2;
+ break;
+ case 'J':
+ DefaultCharIsUnsigned = _True;
+ break;
+ case 'L':
+ if(second == 'D') {
+ AdditionalOptions += option;
+ break;
+ }
+ found = false; break;
+ case 'M':
+ if(second == 'D') {
+ RuntimeLibrary = rtMultiThreadedDLL;
+ if(third == 'd')
+ RuntimeLibrary = rtMultiThreadedDebugDLL;
+ break;
+ } else if(second == 'L') {
+ RuntimeLibrary = rtSingleThreaded;
+ if(third == 'd')
+ RuntimeLibrary = rtSingleThreadedDebug;
+ break;
+ } else if(second == 'T') {
+ RuntimeLibrary = rtMultiThreaded;
+ if(third == 'd')
+ RuntimeLibrary = rtMultiThreadedDebug;
+ break;
+ }
+ found = false; break;
+ case 'O':
+ switch (second) {
+ case '1':
+ Optimization = optimizeMinSpace;
+ break;
+ case '2':
+ Optimization = optimizeMaxSpeed;
+ break;
+ case 'a':
+ AdditionalOptions += option;
+ break;
+ case 'b':
+ if(third == '0')
+ InlineFunctionExpansion = expandDisable;
+ else if(third == '1')
+ InlineFunctionExpansion = expandOnlyInline;
+ else if(third == '2')
+ InlineFunctionExpansion = expandAnySuitable;
+ else
+ found = false;
+ break;
+ case 'd':
+ Optimization = optimizeDisabled;
+ break;
+ case 'g':
+ GlobalOptimizations = _True;
+ break;
+ case 'i':
+ EnableIntrinsicFunctions = _True;
+ break;
+ case 'p':
+ ImproveFloatingPointConsistency = _True;
+ if(third == '-')
+ ImproveFloatingPointConsistency = _False;
+ break;
+ case 's':
+ FavorSizeOrSpeed = favorSize;
+ break;
+ case 't':
+ FavorSizeOrSpeed = favorSpeed;
+ break;
+ case 'w':
+ AdditionalOptions += option;
+ break;
+ case 'x':
+ Optimization = optimizeFull;
+ break;
+ case 'y':
+ OmitFramePointers = _True;
+ if(third == '-')
+ OmitFramePointers = _False;
+ break;
+ default:
+ found = false; break;
+ }
+ break;
+ case 'P':
+ GeneratePreprocessedFile = preprocessYes;
+ break;
+ case 'Q':
+ if(second == 'I') {
+ AdditionalOptions += option;
+ break;
+ } else if (second == 'R') {
+ QString opt = option + 3;
+ if (opt == "interwork-return") {
+ InterworkCalls = _True;
+ break;
+ } else if (opt == "arch4") {
+ CompileForArchitecture = archArmv4;
+ break;
+ } else if (opt == "arch5") {
+ CompileForArchitecture = archArmv5;
+ break;
+ } else if (opt == "arch4T") {
+ CompileForArchitecture = archArmv4T;
+ break;
+ } else if (opt == "arch5T") {
+ CompileForArchitecture = archArmv5T;
+ break;
+ }
+ } else if (second == 'M') {
+ QString opt = option + 3;
+ if (opt == "mips1") {
+ CompileForArchitecture = archMips1;
+ break;
+ }
+ else if (opt == "mips2") {
+ CompileForArchitecture = archMips2;
+ break;
+ }
+ else if (opt == "mips3") {
+ CompileForArchitecture = archMips3;
+ break;
+ }
+ else if (opt == "mips4") {
+ CompileForArchitecture = archMips4;
+ break;
+ }
+ else if (opt == "mips5") {
+ CompileForArchitecture = archMips5;
+ break;
+ }
+ else if (opt == "mips16") {
+ CompileForArchitecture = archMips16;
+ break;
+ }
+ else if (opt == "mips32") {
+ CompileForArchitecture = archMips32;
+ break;
+ }
+ else if (opt == "mips64") {
+ CompileForArchitecture = archMips64;
+ break;
+ }
+ }
+ found = false; break;
+ case 'R':
+ if(second == 'T' && third == 'C') {
+ if(fourth == '1')
+ BasicRuntimeChecks = runtimeBasicCheckAll;
+ else if(fourth == 'c')
+ SmallerTypeCheck = _True;
+ else if(fourth == 's')
+ BasicRuntimeChecks = runtimeCheckStackFrame;
+ else if(fourth == 'u')
+ BasicRuntimeChecks = runtimeCheckUninitVariables;
+ else
+ found = false; break;
+ }
+ break;
+ case 'T':
+ if(second == 'C') {
+ CompileAs = compileAsC;
+ } else if(second == 'P') {
+ CompileAs = compileAsCPlusPlus;
+ } else {
+ qWarning("Generator: Options '/Tp<filename>' and '/Tc<filename>' are not supported by qmake");
+ found = false; break;
+ }
+ break;
+ case 'U':
+ UndefinePreprocessorDefinitions += option+2;
+ break;
+ case 'V':
+ AdditionalOptions += option;
+ break;
+ case 'W':
+ switch (second) {
+ case 'a':
+ case '4':
+ WarningLevel = warningLevel_4;
+ break;
+ case '3':
+ WarningLevel = warningLevel_3;
+ break;
+ case '2':
+ WarningLevel = warningLevel_2;
+ break;
+ case '1':
+ WarningLevel = warningLevel_1;
+ break;
+ case '0':
+ WarningLevel = warningLevel_0;
+ break;
+ case 'L':
+ AdditionalOptions += option;
+ break;
+ case 'X':
+ WarnAsError = _True;
+ break;
+ case 'p':
+ if(third == '6' && fourth == '4') {
+ Detect64BitPortabilityProblems = _True;
+ break;
+ }
+ // Fallthrough
+ default:
+ found = false; break;
+ }
+ break;
+ case 'X':
+ IgnoreStandardIncludePath = _True;
+ break;
+ case 'Y':
+ switch (second) {
+ case '\0':
+ case '-':
+ AdditionalOptions += option;
+ break;
+ case 'X':
+ UsePrecompiledHeader = pchGenerateAuto;
+ PrecompiledHeaderFile = option+3;
+ break;
+ case 'c':
+ UsePrecompiledHeader = pchCreateUsingSpecific;
+ PrecompiledHeaderFile = option+3;
+ break;
+ case 'd':
+ case 'l':
+ AdditionalOptions += option;
+ break;
+ case 'u':
+ UsePrecompiledHeader = pchUseUsingSpecific;
+ PrecompiledHeaderFile = option+3;
+ break;
+ default:
+ found = false; break;
+ }
+ break;
+ case 'Z':
+ switch (second) {
+ case '7':
+ DebugInformationFormat = debugOldStyleInfo;
+ break;
+ case 'I':
+ DebugInformationFormat = debugEditAndContinue;
+ break;
+ case 'd':
+ DebugInformationFormat = debugLineInfoOnly;
+ break;
+ case 'i':
+ DebugInformationFormat = debugEnabled;
+ break;
+ case 'l':
+ DebugInformationFormat = debugEditAndContinue;
+ break;
+ case 'a':
+ DisableLanguageExtensions = _True;
+ break;
+ case 'e':
+ DisableLanguageExtensions = _False;
+ break;
+ case 'c':
+ if(third == ':') {
+ const char *c = option + 4;
+ // Go to the end of the option
+ while ( *c != '\0' && *c != ' ' && *c != '-')
+ ++c;
+ if(fourth == 'f')
+ ForceConformanceInForLoopScope = ((*c) == '-' ? _False : _True);
+ else if(fourth == 'w')
+ TreatWChar_tAsBuiltInType = ((*c) == '-' ? _False : _True);
+ else
+ found = false;
+ } else {
+ found = false; break;
+ }
+ break;
+ case 'g':
+ case 'm':
+ case 's':
+ AdditionalOptions += option;
+ break;
+ case 'p':
+ switch (third)
+ {
+ case '\0':
+ case '1':
+ StructMemberAlignment = alignSingleByte;
+ if(fourth == '6')
+ StructMemberAlignment = alignSixteenBytes;
+ break;
+ case '2':
+ StructMemberAlignment = alignTwoBytes;
+ break;
+ case '4':
+ StructMemberAlignment = alignFourBytes;
+ break;
+ case '8':
+ StructMemberAlignment = alignEightBytes;
+ break;
+ default:
+ found = false; break;
+ }
+ break;
+ default:
+ found = false; break;
+ }
+ break;
+ case 'a':
+ if (second == 'r' && third == 'c' && fourth == 'h') {
+ if (option[5] == ':') {
+ const char *o = option;
+ if (o[6] == 'S' && o[7] == 'S' && o[8] == 'E') {
+ EnableEnhancedInstructionSet = o[9] == '2' ? archSSE2 : archSSE;
+ break;
+ }
+ }
+ }
+ found = false;
+ break;
+ case 'b': // see http://msdn2.microsoft.com/en-us/library/ms173499.aspx
+ if (second == 'i' && third == 'g' && fourth == 'o') {
+ const char *o = option;
+ if (o[5] == 'b' && o[6] == 'j') {
+ AdditionalOptions += option;
+ break;
+ }
+ }
+ found = false;
+ break;
+ case 'c':
+ if(second == '\0') {
+ CompileOnly = _True;
+ } else if(second == 'l') {
+ if (config->CompilerVersion < NET2005) {
+ if(*(option+5) == 'n') {
+ CompileAsManaged = managedAssemblyPure;
+ TurnOffAssemblyGeneration = _True;
+ } else if(*(option+5) == 'p') {
+ CompileAsManaged = managedAssemblyPure;
+ warn_msg(WarnLogic, "/clr:pure option only for .NET >= 2005, using /clr");
+ } else if(*(option+5) == 's') {
+ CompileAsManaged = managedAssemblyPure;
+ warn_msg(WarnLogic, "/clr:safe option only for .NET >= 2005, using /clr");
+ } else if(*(option+5) == 'o') {
+ CompileAsManaged = managedAssemblyPure;
+ warn_msg(WarnLogic, "/clr:oldSyntax option only for .NET >= 2005, using /clr");
+ } else if(*(option+5) == 'i') {
+ CompileAsManaged = managedAssemblyPure;
+ warn_msg(WarnLogic, "initialAppDomain enum value unknown, using /crl");
+ } else {
+ CompileAsManaged = managedAssemblyPure;
+ }
+ } else {
+ if(*(option+5) == 'n') {
+ CompileAsManaged = managedAssembly;
+ TurnOffAssemblyGeneration = _True;
+ } else if(*(option+5) == 'p') {
+ CompileAsManaged = managedAssemblyPure;
+ } else if(*(option+5) == 's') {
+ CompileAsManaged = managedAssemblySafe;
+ } else if(*(option+5) == 'o') {
+ CompileAsManaged = managedAssemblyOldSyntax;
+ } else if(*(option+5) == 'i') {
+ CompileAsManaged = managedAssembly;
+ warn_msg(WarnLogic, "initialAppDomain enum value unknown, using /crl default");
+ } else {
+ CompileAsManaged = managedAssembly;
+ }
+ }
+ } else {
+ found = false; break;
+ }
+ break;
+ case 'd':
+ if(second != 'r') {
+ found = false; break;
+ }
+ CompileAsManaged = managedAssembly;
+ break;
+ case 'f':
+ if(second == 'p' && third == ':') {
+ // Go to the end of the option
+ const char *c = option + 4;
+ while (*c != '\0' && *c != ' ' && *c != '-')
+ ++c;
+ switch (fourth) {
+ case 'e':
+ FloatingPointExceptions = ((*c) == '-' ? _False : _True);
+ break;
+ case 'f':
+ FloatingPointModel = floatingPointFast;
+ break;
+ case 'p':
+ FloatingPointModel = floatingPointPrecise;
+ break;
+ case 's':
+ FloatingPointModel = floatingPointStrict;
+ break;
+ default:
+ found = false;
+ break;
+ }
+ }
+ break;
+ case 'n':
+ if(second == 'o' && third == 'B' && fourth == 'o') {
+ AdditionalOptions += "/noBool";
+ break;
+ }
+ if(second == 'o' && third == 'l' && fourth == 'o') {
+ SuppressStartupBanner = _True;
+ break;
+ }
+ found = false; break;
+ case 'o':
+ if (second == 'p' && third == 'e' && fourth == 'n') {
+ OpenMP = _True;
+ break;
+ }
+ found = false; break;
+ case 's':
+ if(second == 'h' && third == 'o' && fourth == 'w') {
+ ShowIncludes = _True;
+ break;
+ }
+ found = false; break;
+ case 'u':
+ UndefineAllPreprocessorDefinitions = _True;
+ break;
+ case 'v':
+ if(second == 'd' || second == 'm') {
+ AdditionalOptions += option;
+ break;
+ }
+ found = false; break;
+ case 'w':
+ switch (second) {
+ case '\0':
+ WarningLevel = warningLevel_0;
+ break;
+ case 'd':
+ DisableSpecificWarnings += option+3;
+ break;
+ default:
+ AdditionalOptions += option;
+ }
+ break;
+ default:
+ AdditionalOptions += option;
+ break;
+ }
+ if(!found) {
+ warn_msg(WarnLogic, "Could not parse Compiler option: %s, added as AdditionalOption", option);
+ AdditionalOptions += option;
+ }
+ return true;
+}
+
+// VCLinkerTool -----------------------------------------------------
+VCLinkerTool::VCLinkerTool()
+ : EnableCOMDATFolding(optFoldingDefault),
+ GenerateDebugInformation(unset),
+ GenerateMapFile(unset),
+ HeapCommitSize(-1),
+ HeapReserveSize(-1),
+ IgnoreAllDefaultLibraries(unset),
+ IgnoreEmbeddedIDL(unset),
+ IgnoreImportLibrary(_True),
+ LargeAddressAware(addrAwareDefault),
+ LinkDLL(unset),
+ LinkIncremental(linkIncrementalDefault),
+ LinkTimeCodeGeneration(optLTCGDefault),
+ MapExports(unset),
+ MapLines(unset),
+ OptimizeForWindows98(optWin98Default),
+ OptimizeReferences(optReferencesDefault),
+ RegisterOutput(unset),
+ ResourceOnlyDLL(unset),
+ SetChecksum(unset),
+ ShowProgress(linkProgressNotSet),
+ StackCommitSize(-1),
+ StackReserveSize(-1),
+ SubSystem(subSystemNotSet),
+ SupportUnloadOfDelayLoadedDLL(unset),
+ SuppressStartupBanner(unset),
+ SwapRunFromCD(unset),
+ SwapRunFromNet(unset),
+ TargetMachine(machineNotSet),
+ TerminalServerAware(termSvrAwareDefault),
+ TurnOffAssemblyGeneration(unset),
+ TypeLibraryResourceID(0)
+{
+}
+
+XmlOutput &operator<<(XmlOutput &xml, const VCLinkerTool &tool)
+{
+ return xml
+ << tag(_Tool)
+ << attrS(_Name, _VCLinkerTool)
+ << attrX(_AdditionalDependencies, tool.AdditionalDependencies, " ")
+ << attrX(_AdditionalLibraryDirectories, tool.AdditionalLibraryDirectories)
+ << attrX(_AdditionalOptions, tool.AdditionalOptions, " ")
+ << attrX(_AddModuleNamesToAssembly, tool.AddModuleNamesToAssembly)
+ << attrS(_BaseAddress, tool.BaseAddress)
+ << attrX(_DelayLoadDLLs, tool.DelayLoadDLLs)
+ << attrE(_EnableCOMDATFolding, tool.EnableCOMDATFolding, /*ifNot*/ optFoldingDefault)
+ << attrS(_EntryPointSymbol, tool.EntryPointSymbol)
+ << attrX(_ForceSymbolReferences, tool.ForceSymbolReferences)
+ << attrS(_FunctionOrder, tool.FunctionOrder)
+ << attrT(_GenerateDebugInformation, tool.GenerateDebugInformation)
+ << attrT(_GenerateMapFile, tool.GenerateMapFile)
+ << attrL(_HeapCommitSize, tool.HeapCommitSize, /*ifNot*/ -1)
+ << attrL(_HeapReserveSize, tool.HeapReserveSize, /*ifNot*/ -1)
+ << attrT(_IgnoreAllDefaultLibraries, tool.IgnoreAllDefaultLibraries)
+ << attrX(_IgnoreDefaultLibraryNames, tool.IgnoreDefaultLibraryNames)
+ << attrT(_IgnoreEmbeddedIDL, tool.IgnoreEmbeddedIDL)
+ << attrT(_IgnoreImportLibrary, tool.IgnoreImportLibrary)
+ << attrS(_ImportLibrary, tool.ImportLibrary)
+ << attrE(_LargeAddressAware, tool.LargeAddressAware, /*ifNot*/ addrAwareDefault)
+ << attrT(_LinkDLL, tool.LinkDLL)
+ << attrE(_LinkIncremental, tool.LinkIncremental, /*ifNot*/ linkIncrementalDefault)
+ << attrE(_LinkTimeCodeGeneration, tool.LinkTimeCodeGeneration)
+ << attrS(_LinkToManagedResourceFile, tool.LinkToManagedResourceFile)
+ << attrT(_MapExports, tool.MapExports)
+ << attrS(_MapFileName, tool.MapFileName)
+ << attrT(_MapLines, tool.MapLines)
+ << attrS(_MergedIDLBaseFileName, tool.MergedIDLBaseFileName)
+ << attrS(_MergeSections, tool.MergeSections)
+ << attrS(_MidlCommandFile, tool.MidlCommandFile)
+ << attrS(_ModuleDefinitionFile, tool.ModuleDefinitionFile)
+ << attrE(_OptimizeForWindows98, tool.OptimizeForWindows98, /*ifNot*/ optWin98Default)
+ << attrE(_OptimizeReferences, tool.OptimizeReferences, /*ifNot*/ optReferencesDefault)
+ << attrS(_OutputFile, tool.OutputFile)
+ << attr(_ProgramDatabaseFile, tool.ProgramDatabaseFile)
+ << attrT(_RegisterOutput, tool.RegisterOutput)
+ << attrT(_ResourceOnlyDLL, tool.ResourceOnlyDLL)
+ << attrT(_SetChecksum, tool.SetChecksum)
+ << attrE(_ShowProgress, tool.ShowProgress, /*ifNot*/ linkProgressNotSet)
+ << attrL(_StackCommitSize, tool.StackCommitSize, /*ifNot*/ -1)
+ << attrL(_StackReserveSize, tool.StackReserveSize, /*ifNot*/ -1)
+ << attrS(_StripPrivateSymbols, tool.StripPrivateSymbols)
+ << attrE(_SubSystem, tool.SubSystem)
+ << attrT(_SupportUnloadOfDelayLoadedDLL, tool.SupportUnloadOfDelayLoadedDLL)
+ << attrT(_SuppressStartupBanner, tool.SuppressStartupBanner)
+ << attrT(_SwapRunFromCD, tool.SwapRunFromCD)
+ << attrT(_SwapRunFromNet, tool.SwapRunFromNet)
+ << attrE(_TargetMachine, tool.TargetMachine, /*ifNot*/ machineNotSet)
+ << attrE(_TerminalServerAware, tool.TerminalServerAware, /*ifNot*/ termSvrAwareDefault)
+ << attrT(_TurnOffAssemblyGeneration, tool.TurnOffAssemblyGeneration)
+ << attrS(_TypeLibraryFile, tool.TypeLibraryFile)
+ << attrL(_TypeLibraryResourceID, tool.TypeLibraryResourceID, /*ifNot*/ rcUseDefault)
+ << attrS(_Version, tool.Version)
+ << closetag(_Tool);
+}
+
+// Hashing routine to do fast option lookups ----
+// Slightly rewritten to stop on ':' ',' and '\0'
+// Original routine in qtranslator.cpp ----------
+static uint elfHash(const char* name)
+{
+ const uchar *k;
+ uint h = 0;
+ uint g;
+
+ if(name) {
+ k = (const uchar *) name;
+ while((*k) &&
+ (*k)!= ':' &&
+ (*k)!=',' &&
+ (*k)!=' ') {
+ h = (h << 4) + *k++;
+ if((g = (h & 0xf0000000)) != 0)
+ h ^= g >> 24;
+ h &= ~g;
+ }
+ }
+ if(!h)
+ h = 1;
+ return h;
+}
+
+//#define USE_DISPLAY_HASH
+#ifdef USE_DISPLAY_HASH
+static void displayHash(const char* str)
+{
+ printf("case 0x%07x: // %s\n break;\n", elfHash(str), str);
+}
+#endif
+
+bool VCLinkerTool::parseOption(const char* option)
+{
+#ifdef USE_DISPLAY_HASH
+ // Main options
+ displayHash("/ALIGN"); displayHash("/ALLOWBIND"); displayHash("/ASSEMBLYMODULE");
+ displayHash("/ASSEMBLYRESOURCE"); displayHash("/BASE"); displayHash("/DEBUG");
+ displayHash("/DEF"); displayHash("/DEFAULTLIB"); displayHash("/DELAY");
+ displayHash("/DELAYLOAD"); displayHash("/DLL"); displayHash("/DRIVER");
+ displayHash("/ENTRY"); displayHash("/EXETYPE"); displayHash("/EXPORT");
+ displayHash("/FIXED"); displayHash("/FORCE"); displayHash("/HEAP");
+ displayHash("/IDLOUT"); displayHash("/IGNORE"); displayHash("/IGNOREIDL"); displayHash("/IMPLIB");
+ displayHash("/INCLUDE"); displayHash("/INCREMENTAL"); displayHash("/LARGEADDRESSAWARE");
+ displayHash("/LIBPATH"); displayHash("/LTCG"); displayHash("/MACHINE");
+ displayHash("/MAP"); displayHash("/MAPINFO"); displayHash("/MERGE");
+ displayHash("/MIDL"); displayHash("/NOASSEMBLY"); displayHash("/NODEFAULTLIB");
+ displayHash("/NOENTRY"); displayHash("/NOLOGO"); displayHash("/OPT");
+ displayHash("/ORDER"); displayHash("/OUT"); displayHash("/PDB");
+ displayHash("/PDBSTRIPPED"); displayHash("/RELEASE"); displayHash("/SECTION");
+ displayHash("/STACK"); displayHash("/STUB"); displayHash("/SUBSYSTEM");
+ displayHash("/SWAPRUN"); displayHash("/TLBID"); displayHash("/TLBOUT");
+ displayHash("/TSAWARE"); displayHash("/VERBOSE"); displayHash("/VERSION");
+ displayHash("/VXD"); displayHash("/WS "); displayHash("/libpath");
+
+#endif
+#ifdef USE_DISPLAY_HASH
+ // Sub options
+ displayHash("UNLOAD"); displayHash("NOBIND"); displayHash("no"); displayHash("NOSTATUS"); displayHash("STATUS");
+ displayHash("AM33"); displayHash("ARM"); displayHash("CEE"); displayHash("EBC"); displayHash("IA64"); displayHash("X86"); displayHash("X64"); displayHash("M32R");
+ displayHash("MIPS"); displayHash("MIPS16"); displayHash("MIPSFPU"); displayHash("MIPSFPU16"); displayHash("MIPSR41XX"); displayHash("PPC");
+ displayHash("SH3"); displayHash("SH3DSP"); displayHash("SH4"); displayHash("SH5"); displayHash("THUMB"); displayHash("TRICORE"); displayHash("EXPORTS");
+ displayHash("LINES"); displayHash("REF"); displayHash("NOREF"); displayHash("ICF"); displayHash("WIN98"); displayHash("NOWIN98");
+ displayHash("CONSOLE"); displayHash("EFI_APPLICATION"); displayHash("EFI_BOOT_SERVICE_DRIVER"); displayHash("EFI_ROM"); displayHash("EFI_RUNTIME_DRIVER"); displayHash("NATIVE");
+ displayHash("POSIX"); displayHash("WINDOWS"); displayHash("WINDOWSCE"); displayHash("NET"); displayHash("CD"); displayHash("NO");
+#endif
+ bool found = true;
+ switch (elfHash(option)) {
+ case 0x3360dbe: // /ALIGN[:number]
+ case 0x1485c34: // /ALLOWBIND[:NO]
+ case 0x6b21972: // /DEFAULTLIB:library
+ case 0x396ea92: // /DRIVER[:UPONLY | :WDM]
+ case 0xaca9d75: // /EXETYPE[:DYNAMIC | :DEV386]
+ case 0x3ad5444: // /EXPORT:entryname[,@ordinal[,NONAME]][,DATA]
+ case 0x33aec94: // /FIXED[:NO]
+ case 0x33b4675: // /FORCE:[MULTIPLE|UNRESOLVED]
+ case 0x3dc3455: // /IGNORE:number,number,number,number ### NOTE: This one is undocumented, but it is even used by Microsoft.
+ // In recent versions of the Microsoft linker they have disabled this undocumented feature.
+ case 0x7988f7e: // /SECTION:name,[E][R][W][S][D][K][L][P][X][,ALIGN=#]
+ case 0x0348992: // /STUB:filename
+ case 0x0034bc4: // /VXD
+ case 0x0034c50: // /WS
+ AdditionalOptions += option;
+ break;
+ case 0x679c075: // /ASSEMBLYMODULE:filename
+ AddModuleNamesToAssembly += option+15;
+ break;
+ case 0x062d065: // /ASSEMBLYRESOURCE:filename
+ LinkToManagedResourceFile = option+18;
+ break;
+ case 0x0336675: // /BASE:{address | @filename,key}
+ // Do we need to do a manual lookup when '@filename,key'?
+ // Seems BaseAddress only can contain the location...
+ // We don't use it in Qt, so keep it simple for now
+ BaseAddress = option+6;
+ break;
+ case 0x3389797: // /DEBUG
+ GenerateDebugInformation = _True;
+ break;
+ case 0x0033896: // /DEF:filename
+ ModuleDefinitionFile = option+5;
+ break;
+ case 0x338a069: // /DELAY:{UNLOAD | NOBIND}
+ // MS documentation does not specify what to do with
+ // this option, so we'll put it in AdditionalOptions
+ AdditionalOptions += option;
+ break;
+ case 0x06f4bf4: // /DELAYLOAD:dllname
+ DelayLoadDLLs += option+11;
+ break;
+ case 0x003390c: // /DLL
+ // This option is not used for vcproj files
+ break;
+ case 0x33a3979: // /ENTRY:function
+ EntryPointSymbol = option+7;
+ break;
+ case 0x033c960: // /HEAP:reserve[,commit]
+ {
+ QStringList both = QString(option+6).split(",");
+ HeapReserveSize = both[0].toLongLong();
+ if(both.count() == 2)
+ HeapCommitSize = both[1].toLongLong();
+ }
+ break;
+ case 0x3d91494: // /IDLOUT:[path\]filename
+ MergedIDLBaseFileName = option+8;
+ break;
+ case 0x345a04c: // /IGNOREIDL
+ IgnoreEmbeddedIDL = _True;
+ break;
+ case 0x3e250e2: // /IMPLIB:filename
+ ImportLibrary = option+8;
+ break;
+ case 0xe281ab5: // /INCLUDE:symbol
+ ForceSymbolReferences += option+9;
+ break;
+ case 0xb28103c: // /INCREMENTAL[:no]
+ if(*(option+12) == ':' &&
+ (*(option+13) == 'n' || *(option+13) == 'N'))
+ LinkIncremental = linkIncrementalNo;
+ else
+ LinkIncremental = linkIncrementalYes;
+ break;
+ case 0x26e4675: // /LARGEADDRESSAWARE[:no]
+ if(*(option+18) == ':' &&
+ *(option+19) == 'n')
+ LargeAddressAware = addrAwareNoLarge;
+ else
+ LargeAddressAware = addrAwareLarge;
+ break;
+ case 0x2f96bc8: // /libpath:dir
+ case 0x0d745c8: // /LIBPATH:dir
+ AdditionalLibraryDirectories += option+9;
+ break;
+ case 0x0341877: // /LTCG[:NOSTATUS|:STATUS]
+ config->WholeProgramOptimization = _True;
+ if (config->CompilerVersion >= NET2005) {
+ LinkTimeCodeGeneration = optLTCGEnabled;
+ if(*(option+5) == ':') {
+ const char* str = option+6;
+ if (*str == 'S')
+ ShowProgress = linkProgressAll;
+#ifndef Q_OS_WIN
+ else if (strncasecmp(str, "pginstrument", 12))
+ LinkTimeCodeGeneration = optLTCGInstrument;
+ else if (strncasecmp(str, "pgoptimize", 10))
+ LinkTimeCodeGeneration = optLTCGOptimize;
+ else if (strncasecmp(str, "pgupdate", 8 ))
+ LinkTimeCodeGeneration = optLTCGUpdate;
+#else
+ else if (_stricmp(str, "pginstrument"))
+ LinkTimeCodeGeneration = optLTCGInstrument;
+ else if (_stricmp(str, "pgoptimize"))
+ LinkTimeCodeGeneration = optLTCGOptimize;
+ else if (_stricmp(str, "pgupdate"))
+ LinkTimeCodeGeneration = optLTCGUpdate;
+#endif
+ }
+ } else {
+ AdditionalOptions.append(option);
+ }
+ break;
+ case 0x379ED25:
+ case 0x157cf65: // /MACHINE:{AM33|ARM|CEE|IA64|X86|M32R|MIPS|MIPS16|MIPSFPU|MIPSFPU16|MIPSR41XX|PPC|SH3|SH4|SH5|THUMB|TRICORE}
+ switch (elfHash(option+9)) {
+ // Very limited documentation on all options but X86,
+ case 0x0005bb6: // X86
+ TargetMachine = machineX86;
+ break;
+ // so we put the others in AdditionalOptions...
+ case 0x0005b94: // X64
+ case 0x0046063: // AM33
+ case 0x000466d: // ARM
+ case 0x0004795: // CEE
+ case 0x0004963: // EBC
+ case 0x004d494: // IA64
+ case 0x0050672: // M32R
+ case 0x0051e53: // MIPS
+ case 0x51e5646: // MIPS16
+ case 0x1e57b05: // MIPSFPU
+ case 0x57b09a6: // MIPSFPU16
+ case 0x5852738: // MIPSR41XX
+ case 0x0005543: // PPC
+ case 0x00057b3: // SH3
+ case 0x57b7980: // SH3DSP
+ case 0x00057b4: // SH4
+ case 0x00057b5: // SH5
+ case 0x058da12: // THUMB
+ case 0x96d8435: // TRICORE
+ default:
+ AdditionalOptions += option;
+ break;
+ }
+ break;
+ case 0x0034160: // /MAP[:filename]
+ GenerateMapFile = _True;
+ MapFileName = option+5;
+ break;
+ case 0x164e1ef: // /MAPINFO:{EXPORTS|LINES}
+ if(*(option+9) == 'E')
+ MapExports = _True;
+ else if(*(option+9) == 'L')
+ MapLines = _True;
+ break;
+ case 0x341a6b5: // /MERGE:from=to
+ MergeSections = option+7;
+ break;
+ case 0x0341d8c: // /MIDL:@file
+ MidlCommandFile = option+7;
+ break;
+ case 0x84e2679: // /NOASSEMBLY
+ TurnOffAssemblyGeneration = _True;
+ break;
+ case 0x2b21942: // /NODEFAULTLIB[:library]
+ if(*(option+13) == '\0')
+ IgnoreAllDefaultLibraries = _True;
+ else
+ IgnoreDefaultLibraryNames += option+14;
+ break;
+ case 0x33a3a39: // /NOENTRY
+ ResourceOnlyDLL = _True;
+ break;
+ case 0x434138f: // /NOLOGO
+ SuppressStartupBanner = _True;
+ break;
+ case 0x0034454: // /OPT:{REF | NOREF | ICF[=iterations] | NOICF | WIN98 | NOWIN98}
+ {
+ char third = *(option+7);
+ switch (third) {
+ case 'F': // REF
+ if(*(option+5) == 'R') {
+ OptimizeReferences = optReferences;
+ } else { // ICF[=iterations]
+ EnableCOMDATFolding = optFolding;
+ // [=iterations] case is not documented
+ }
+ break;
+ case 'R': // NOREF
+ OptimizeReferences = optNoReferences;
+ break;
+ case 'I': // NOICF
+ EnableCOMDATFolding = optNoFolding;
+ break;
+ case 'N': // WIN98
+ OptimizeForWindows98 = optWin98Yes;
+ break;
+ case 'W': // NOWIN98
+ OptimizeForWindows98 = optWin98No;
+ break;
+ default:
+ found = false;
+ }
+ }
+ break;
+ case 0x34468a2: // /ORDER:@filename
+ FunctionOrder = option+8;
+ break;
+ case 0x00344a4: // /OUT:filename
+ OutputFile = option+5;
+ break;
+ case 0x0034482: // /PDB:filename
+ ProgramDatabaseFile = option+5;
+ break;
+ case 0xa2ad314: // /PDBSTRIPPED:pdb_file_name
+ StripPrivateSymbols = option+13;
+ break;
+ case 0x6a09535: // /RELEASE
+ SetChecksum = _True;
+ break;
+ case 0x348857b: // /STACK:reserve[,commit]
+ {
+ QStringList both = QString(option+7).split(",");
+ StackReserveSize = both[0].toLongLong();
+ if(both.count() == 2)
+ StackCommitSize = both[1].toLongLong();
+ }
+ break;
+ case 0x75AA4D8: // /SAFESH:{NO}
+ {
+ AdditionalOptions += option;
+ break;
+ }
+ case 0x9B3C00D:
+ case 0x78dc00d: // /SUBSYSTEM:{CONSOLE|EFI_APPLICATION|EFI_BOOT_SERVICE_DRIVER|EFI_ROM|EFI_RUNTIME_DRIVER|NATIVE|POSIX|WINDOWS|WINDOWSCE}[,major[.minor]]
+ {
+ // Split up in subsystem, and version number
+ QStringList both = QString(option+11).split(",");
+ switch (elfHash(both[0].toLatin1())) {
+ case 0x8438445: // CONSOLE
+ SubSystem = subSystemConsole;
+ break;
+ case 0xbe29493: // WINDOWS
+ SubSystem = subSystemWindows;
+ break;
+ // The following are undocumented, so add them to AdditionalOptions
+ case 0x240949e: // EFI_APPLICATION
+ case 0xe617652: // EFI_BOOT_SERVICE_DRIVER
+ case 0x9af477d: // EFI_ROM
+ case 0xd34df42: // EFI_RUNTIME_DRIVER
+ case 0x5268ea5: // NATIVE
+ case 0x05547e8: // POSIX
+ case 0x2949c95: // WINDOWSCE
+ case 0x4B69795: // windowsce
+ AdditionalOptions += option;
+ break;
+ default:
+ found = false;
+ }
+ }
+ break;
+ case 0x8b654de: // /SWAPRUN:{NET | CD}
+ if(*(option+9) == 'N')
+ SwapRunFromNet = _True;
+ else if(*(option+9) == 'C')
+ SwapRunFromCD = _True;
+ else
+ found = false;
+ break;
+ case 0x34906d4: // /TLBID:id
+ TypeLibraryResourceID = QString(option+7).toLongLong();
+ break;
+ case 0x4907494: // /TLBOUT:[path\]filename
+ TypeLibraryFile = option+8;
+ break;
+ case 0x976b525: // /TSAWARE[:NO]
+ if(*(option+8) == ':')
+ TerminalServerAware = termSvrAwareNo;
+ else
+ TerminalServerAware = termSvrAwareYes;
+ break;
+ case 0xaa67735: // /VERBOSE[:lib]
+ if(*(option+9) == ':') {
+ ShowProgress = linkProgressLibs;
+ AdditionalOptions += option;
+ } else {
+ ShowProgress = linkProgressAll;
+ }
+ break;
+ case 0xaa77f7e: // /VERSION:major[.minor]
+ Version = option+9;
+ break;
+ default:
+ AdditionalOptions += option;
+ break;
+ }
+ if(!found) {
+ warn_msg(WarnLogic, "Could not parse Linker options: %s, added as AdditionalOption", option);
+ AdditionalOptions += option;
+ }
+ return found;
+}
+
+// VCMIDLTool -------------------------------------------------------
+VCMIDLTool::VCMIDLTool()
+ : DefaultCharType(midlCharUnsigned),
+ EnableErrorChecks(midlDisableAll),
+ ErrorCheckAllocations(unset),
+ ErrorCheckBounds(unset),
+ ErrorCheckEnumRange(unset),
+ ErrorCheckRefPointers(unset),
+ ErrorCheckStubData(unset),
+ GenerateStublessProxies(unset),
+ GenerateTypeLibrary(unset),
+ IgnoreStandardIncludePath(unset),
+ MkTypLibCompatible(unset),
+ StructMemberAlignment(midlAlignNotSet),
+ SuppressStartupBanner(unset),
+ TargetEnvironment(midlTargetNotSet),
+ ValidateParameters(unset),
+ WarnAsError(unset),
+ WarningLevel(midlWarningLevel_0)
+{
+}
+
+XmlOutput &operator<<(XmlOutput &xml, const VCMIDLTool &tool)
+{
+ return xml
+ << tag(_Tool)
+ << attrS(_Name, _VCMIDLTool)
+ << attrX(_AdditionalIncludeDirectories, tool.AdditionalIncludeDirectories)
+ << attrX(_AdditionalOptions, tool.AdditionalOptions, " ")
+ << attrX(_CPreprocessOptions, tool.CPreprocessOptions)
+ << attrE(_DefaultCharType, tool.DefaultCharType)
+ << attrS(_DLLDataFileName, tool.DLLDataFileName)
+ << attrE(_EnableErrorChecks, tool.EnableErrorChecks)
+ << attrT(_ErrorCheckAllocations, tool.ErrorCheckAllocations)
+ << attrT(_ErrorCheckBounds, tool.ErrorCheckBounds)
+ << attrT(_ErrorCheckEnumRange, tool.ErrorCheckEnumRange)
+ << attrT(_ErrorCheckRefPointers, tool.ErrorCheckRefPointers)
+ << attrT(_ErrorCheckStubData, tool.ErrorCheckStubData)
+ << attrX(_FullIncludePath, tool.FullIncludePath)
+ << attrT(_GenerateStublessProxies, tool.GenerateStublessProxies)
+ << attrT(_GenerateTypeLibrary, tool.GenerateTypeLibrary)
+ << attrS(_HeaderFileName, tool.HeaderFileName)
+ << attrT(_IgnoreStandardIncludePath, tool.IgnoreStandardIncludePath)
+ << attrS(_InterfaceIdentifierFileName, tool.InterfaceIdentifierFileName)
+ << attrT(_MkTypLibCompatible, tool.MkTypLibCompatible)
+ << attrS(_OutputDirectory, tool.OutputDirectory)
+ << attrX(_PreprocessorDefinitions, tool.PreprocessorDefinitions)
+ << attrS(_ProxyFileName, tool.ProxyFileName)
+ << attrS(_RedirectOutputAndErrors, tool.RedirectOutputAndErrors)
+ << attrE(_StructMemberAlignment, tool.StructMemberAlignment, /*ifNot*/ midlAlignNotSet)
+ << attrT(_SuppressStartupBanner, tool.SuppressStartupBanner)
+ << attrE(_TargetEnvironment, tool.TargetEnvironment, /*ifNot*/ midlTargetNotSet)
+ << attrS(_TypeLibraryName, tool.TypeLibraryName)
+ << attrX(_UndefinePreprocessorDefinitions, tool.UndefinePreprocessorDefinitions)
+ << attrT(_ValidateParameters, tool.ValidateParameters)
+ << attrT(_WarnAsError, tool.WarnAsError)
+ << attrE(_WarningLevel, tool.WarningLevel)
+ << closetag(_Tool);
+}
+
+bool VCMIDLTool::parseOption(const char* option)
+{
+#ifdef USE_DISPLAY_HASH
+ displayHash("/D name[=def]"); displayHash("/I directory-list"); displayHash("/Oi");
+ displayHash("/Oic"); displayHash("/Oicf"); displayHash("/Oif"); displayHash("/Os");
+ displayHash("/U name"); displayHash("/WX"); displayHash("/W{0|1|2|3|4}");
+ displayHash("/Zp {N}"); displayHash("/Zs"); displayHash("/acf filename");
+ displayHash("/align {N}"); displayHash("/app_config"); displayHash("/c_ext");
+ displayHash("/char ascii7"); displayHash("/char signed"); displayHash("/char unsigned");
+ displayHash("/client none"); displayHash("/client stub"); displayHash("/confirm");
+ displayHash("/cpp_cmd cmd_line"); displayHash("/cpp_opt options");
+ displayHash("/cstub filename"); displayHash("/dlldata filename"); displayHash("/env win32");
+ displayHash("/env win64"); displayHash("/error all"); displayHash("/error allocation");
+ displayHash("/error bounds_check"); displayHash("/error enum"); displayHash("/error none");
+ displayHash("/error ref"); displayHash("/error stub_data"); displayHash("/h filename");
+ displayHash("/header filename"); displayHash("/iid filename"); displayHash("/lcid");
+ displayHash("/mktyplib203"); displayHash("/ms_ext"); displayHash("/ms_union");
+ displayHash("/msc_ver <nnnn>"); displayHash("/newtlb"); displayHash("/no_cpp");
+ displayHash("/no_def_idir"); displayHash("/no_default_epv"); displayHash("/no_format_opt");
+ displayHash("/no_warn"); displayHash("/nocpp"); displayHash("/nologo"); displayHash("/notlb");
+ displayHash("/o filename"); displayHash("/oldnames"); displayHash("/oldtlb");
+ displayHash("/osf"); displayHash("/out directory"); displayHash("/pack {N}");
+ displayHash("/prefix all"); displayHash("/prefix client"); displayHash("/prefix server");
+ displayHash("/prefix switch"); displayHash("/protocol all"); displayHash("/protocol dce");
+ displayHash("/protocol ndr64"); displayHash("/proxy filename"); displayHash("/robust");
+ displayHash("/rpcss"); displayHash("/savePP"); displayHash("/server none");
+ displayHash("/server stub"); displayHash("/sstub filename"); displayHash("/syntax_check");
+ displayHash("/target {system}"); displayHash("/tlb filename"); displayHash("/use_epv");
+ displayHash("/win32"); displayHash("/win64");
+#endif
+ bool found = true;
+ int offset = 0;
+ switch(elfHash(option)) {
+ case 0x0000334: // /D name[=def]
+ PreprocessorDefinitions += option+3;
+ break;
+ case 0x0000339: // /I directory-list
+ AdditionalIncludeDirectories += option+3;
+ break;
+ case 0x0345f96: // /Oicf
+ case 0x00345f6: // /Oif
+ GenerateStublessProxies = _True;
+ break;
+ case 0x0000345: // /U name
+ UndefinePreprocessorDefinitions += option+3;
+ break;
+ case 0x00034c8: // /WX
+ WarnAsError = _True;
+ break;
+ case 0x3582fde: // /align {N}
+ offset = 3; // Fallthrough
+ case 0x0003510: // /Zp {N}
+ switch (*(option+offset+4)) {
+ case '1':
+ StructMemberAlignment = (*(option+offset+5) == '\0') ? midlAlignSingleByte : midlAlignSixteenBytes;
+ break;
+ case '2':
+ StructMemberAlignment = midlAlignTwoBytes;
+ break;
+ case '4':
+ StructMemberAlignment = midlAlignFourBytes;
+ break;
+ case '8':
+ StructMemberAlignment = midlAlignEightBytes;
+ break;
+ default:
+ found = false;
+ }
+ break;
+ case 0x0359e82: // /char {ascii7|signed|unsigned}
+ switch(*(option+6)) {
+ case 'a':
+ DefaultCharType = midlCharAscii7;
+ break;
+ case 's':
+ DefaultCharType = midlCharSigned;
+ break;
+ case 'u':
+ DefaultCharType = midlCharUnsigned;
+ break;
+ default:
+ found = false;
+ }
+ break;
+ case 0xa766524: // /cpp_opt options
+ CPreprocessOptions += option+9;
+ break;
+ case 0xb32abf1: // /dlldata filename
+ DLLDataFileName = option + 9;
+ break;
+ case 0x0035c56: // /env {win32|win64}
+ TargetEnvironment = (*(option+8) == '6') ? midlTargetWin64 : midlTargetWin32;
+ break;
+ case 0x35c9962: // /error {all|allocation|bounds_check|enum|none|ref|stub_data}
+ EnableErrorChecks = midlEnableCustom;
+ switch (*(option+7)) {
+ case 'a':
+ if(*(option+10) == '\0')
+ EnableErrorChecks = midlEnableAll;
+ else
+ ErrorCheckAllocations = _True;
+ break;
+ case 'b':
+ ErrorCheckBounds = _True;
+ break;
+ case 'e':
+ ErrorCheckEnumRange = _True;
+ break;
+ case 'n':
+ EnableErrorChecks = midlDisableAll;
+ break;
+ case 'r':
+ ErrorCheckRefPointers = _True;
+ break;
+ case 's':
+ ErrorCheckStubData = _True;
+ break;
+ default:
+ found = false;
+ }
+ break;
+ case 0x5eb7af2: // /header filename
+ offset = 5;
+ case 0x0000358: // /h filename
+ HeaderFileName = option + offset + 3;
+ break;
+ case 0x0035ff4: // /iid filename
+ InterfaceIdentifierFileName = option+5;
+ break;
+ case 0x64b7933: // /mktyplib203
+ MkTypLibCompatible = _True;
+ break;
+ case 0x8e0b0a2: // /no_def_idir
+ IgnoreStandardIncludePath = _True;
+ break;
+ case 0x65635ef: // /nologo
+ SuppressStartupBanner = _True;
+ break;
+ case 0x3656b22: // /notlb
+ GenerateTypeLibrary = _True;
+ break;
+ case 0x000035f: // /o filename
+ RedirectOutputAndErrors = option+3;
+ break;
+ case 0x00366c4: // /out directory
+ OutputDirectory = option+5;
+ break;
+ case 0x36796f9: // /proxy filename
+ ProxyFileName = option+7;
+ break;
+ case 0x6959c94: // /robust
+ ValidateParameters = _True;
+ break;
+ case 0x6a88df4: // /target {system}
+ if(*(option+11) == '6')
+ TargetEnvironment = midlTargetWin64;
+ else
+ TargetEnvironment = midlTargetWin32;
+ break;
+ case 0x0036b22: // /tlb filename
+ TypeLibraryName = option+5;
+ break;
+ case 0x36e0162: // /win32
+ TargetEnvironment = midlTargetWin32;
+ break;
+ case 0x36e0194: // /win64
+ TargetEnvironment = midlTargetWin64;
+ break;
+ case 0x0003459: // /Oi
+ case 0x00345f3: // /Oic
+ case 0x0003463: // /Os
+ case 0x0003513: // /Zs
+ case 0x0035796: // /acf filename
+ case 0x5b1cb97: // /app_config
+ case 0x3595cf4: // /c_ext
+ case 0x5a2fc64: // /client {none|stub}
+ case 0xa64d3dd: // /confirm
+ case 0xa765b64: // /cpp_cmd cmd_line
+ case 0x35aabb2: // /cstub filename
+ case 0x03629f4: // /lcid
+ case 0x6495cc4: // /ms_ext
+ case 0x96c7a1e: // /ms_union
+ case 0x4996fa2: // /msc_ver <nnnn>
+ case 0x64ceb12: // /newtlb
+ case 0x6555a40: // /no_cpp
+ case 0xf64d6a6: // /no_default_epv
+ case 0x6dd9384: // /no_format_opt
+ case 0x556dbee: // /no_warn
+ case 0x3655a70: // /nocpp
+ case 0x2b455a3: // /oldnames
+ case 0x662bb12: // /oldtlb
+ case 0x0036696: // /osf
+ case 0x036679b: // /pack {N}
+ case 0x678bd38: // /prefix {all|client|server|switch}
+ case 0x96b702c: // /protocol {all|dce|ndr64}
+ case 0x3696aa3: // /rpcss
+ case 0x698ca60: // /savePP
+ case 0x69c9cf2: // /server {none|stub}
+ case 0x36aabb2: // /sstub filename
+ case 0xce9b12b: // /syntax_check
+ case 0xc9b5f16: // /use_epv
+ AdditionalOptions += option;
+ break;
+ default:
+ // /W{0|1|2|3|4} case
+ if(*(option+1) == 'W') {
+ switch (*(option+2)) {
+ case '0':
+ WarningLevel = midlWarningLevel_0;
+ break;
+ case '1':
+ WarningLevel = midlWarningLevel_1;
+ break;
+ case '2':
+ WarningLevel = midlWarningLevel_2;
+ break;
+ case '3':
+ WarningLevel = midlWarningLevel_3;
+ break;
+ case '4':
+ WarningLevel = midlWarningLevel_4;
+ break;
+ default:
+ found = false;
+ }
+ }
+ break;
+ }
+ if(!found)
+ warn_msg(WarnLogic, "Could not parse MIDL option: %s", option);
+ return true;
+}
+
+// VCLibrarianTool --------------------------------------------------
+VCLibrarianTool::VCLibrarianTool()
+ : IgnoreAllDefaultLibraries(unset),
+ SuppressStartupBanner(_True)
+{
+}
+
+XmlOutput &operator<<(XmlOutput &xml, const VCLibrarianTool &tool)
+{
+ return xml
+ << tag(_Tool)
+ << attrS(_Name, _VCLibrarianTool)
+ << attrX(_AdditionalDependencies, tool.AdditionalDependencies)
+ << attrX(_AdditionalLibraryDirectories, tool.AdditionalLibraryDirectories)
+ << attrX(_AdditionalOptions, tool.AdditionalOptions, " ")
+ << attrX(_ExportNamedFunctions, tool.ExportNamedFunctions)
+ << attrX(_ForceSymbolReferences, tool.ForceSymbolReferences)
+ << attrT(_IgnoreAllDefaultLibraries, tool.IgnoreAllDefaultLibraries)
+ << attrX(_IgnoreDefaultLibraryNames, tool.IgnoreDefaultLibraryNames)
+ << attrS(_ModuleDefinitionFile, tool.ModuleDefinitionFile)
+ << attrS(_OutputFile, tool.OutputFile)
+ << attrT(_SuppressStartupBanner, tool.SuppressStartupBanner)
+ << closetag(_Tool);
+}
+
+// VCCustomBuildTool ------------------------------------------------
+VCCustomBuildTool::VCCustomBuildTool()
+{
+ ToolName = "VCCustomBuildTool";
+}
+
+XmlOutput &operator<<(XmlOutput &xml, const VCCustomBuildTool &tool)
+{
+ // The code below offers two ways to split custom build step commands.
+ // Normally the $$escape_expand(\n\t) is used in a project file, which is correctly translated
+ // in all generators. However, if you use $$escape_expand(\n\r) (or \n\h) instead, the VCPROJ
+ // generator will instead of binding the commands with " && " will insert a proper newline into
+ // the VCPROJ file. We sometimes use this method of splitting commands if the custom buildstep
+ // contains a command-line which is too big to run on certain OS.
+ QString cmds;
+ int end = tool.CommandLine.count();
+ for(int i = 0; i < end; ++i) {
+ QString cmdl = tool.CommandLine.at(i);
+ if (cmdl.contains("\r\t")) {
+ if (i == end - 1)
+ cmdl = cmdl.trimmed();
+ cmdl.replace("\r\t", " && ");
+ } else if (cmdl.contains("\r\n")) {
+ ;
+ } else if (cmdl.contains("\r\\h")) {
+ // The above \r\n should work, but doesn't, so we have this hack
+ cmdl.replace("\r\\h", "\r\n");
+ } else {
+ if (i < end - 1)
+ cmdl += " && ";
+ }
+ cmds += cmdl;
+ }
+ return xml
+ << tag(_Tool)
+ << attrS(_Name, tool.ToolName)
+ << attrX(_AdditionalDependencies, tool.AdditionalDependencies, ";")
+ << attrS(_CommandLine, cmds)
+ << attrS(_Description, tool.Description)
+ << attrX(_Outputs, tool.Outputs, ";")
+ << attrS(_Path, tool.ToolPath)
+ << closetag(_Tool);
+}
+
+// VCResourceCompilerTool -------------------------------------------
+VCResourceCompilerTool::VCResourceCompilerTool()
+ : Culture(rcUseDefault),
+ IgnoreStandardIncludePath(unset),
+ ShowProgress(linkProgressNotSet)
+{
+ PreprocessorDefinitions = QStringList("NDEBUG");
+}
+
+XmlOutput &operator<<(XmlOutput &xml, const VCResourceCompilerTool &tool)
+{
+ return xml
+ << tag(_Tool)
+ << attrS(_Name, _VCResourceCompilerTool)
+ << attrS(_Path, tool.ToolPath)
+ << attrX(_AdditionalIncludeDirectories, tool.AdditionalIncludeDirectories)
+ << attrX(_AdditionalOptions, tool.AdditionalOptions, " ")
+ << attrE(_Culture, tool.Culture, /*ifNot*/ rcUseDefault)
+ << attrX(_FullIncludePath, tool.FullIncludePath)
+ << attrT(_IgnoreStandardIncludePath, tool.IgnoreStandardIncludePath)
+ << attrX(_PreprocessorDefinitions, tool.PreprocessorDefinitions)
+ << attrS(_ResourceOutputFileName, tool.ResourceOutputFileName)
+ << attrE(_ShowProgress, tool.ShowProgress, /*ifNot*/ linkProgressNotSet)
+ << closetag(_Tool);
+}
+
+// VCDeploymentTool --------------------------------------------
+VCDeploymentTool::VCDeploymentTool()
+ : RegisterOutput(registerNo)
+{
+ DeploymentTag = "DeploymentTool";
+ RemoteDirectory = "";
+}
+
+XmlOutput &operator<<(XmlOutput &xml, const VCDeploymentTool &tool)
+{
+ if (tool.AdditionalFiles.isEmpty())
+ return xml;
+ return xml
+ << tag(tool.DeploymentTag)
+ << attrS(_RemoteDirectory, tool.RemoteDirectory)
+ << attrE(_RegisterOutput, tool.RegisterOutput)
+ << attrS(_AdditionalFiles, tool.AdditionalFiles)
+ << closetag(tool.DeploymentTag);
+}
+
+// VCEventTool -------------------------------------------------
+XmlOutput &operator<<(XmlOutput &xml, const VCEventTool &tool)
+{
+ return xml
+ << tag(_Tool)
+ << attrS(_Name, tool.ToolName)
+ << attrS(_Path, tool.ToolPath)
+ << attrS(_CommandLine, tool.CommandLine)
+ << attrS(_Description, tool.Description)
+ << attrT(_ExcludedFromBuild, tool.ExcludedFromBuild)
+ << closetag(_Tool);
+}
+
+// VCPostBuildEventTool ---------------------------------------------
+VCPostBuildEventTool::VCPostBuildEventTool()
+{
+ ToolName = "VCPostBuildEventTool";
+}
+
+// VCPreBuildEventTool ----------------------------------------------
+VCPreBuildEventTool::VCPreBuildEventTool()
+{
+ ToolName = "VCPreBuildEventTool";
+}
+
+// VCPreLinkEventTool -----------------------------------------------
+VCPreLinkEventTool::VCPreLinkEventTool()
+{
+ ToolName = "VCPreLinkEventTool";
+}
+
+// VCConfiguration --------------------------------------------------
+
+VCConfiguration::VCConfiguration()
+ : ATLMinimizesCRunTimeLibraryUsage(unset),
+ BuildBrowserInformation(unset),
+ CharacterSet(charSetNotSet),
+ ConfigurationType(typeApplication),
+ RegisterOutput(unset),
+ UseOfATL(useATLNotSet),
+ UseOfMfc(useMfcStdWin),
+ WholeProgramOptimization(unset)
+{
+ compiler.config = this;
+ linker.config = this;
+ idl.config = this;
+}
+
+XmlOutput &operator<<(XmlOutput &xml, const VCConfiguration &tool)
+{
+ xml << tag(_Configuration)
+ << attrS(_Name, tool.Name)
+ << attrS(_OutputDirectory, tool.OutputDirectory)
+ << attrT(_ATLMinimizesCRunTimeLibraryUsage, tool.ATLMinimizesCRunTimeLibraryUsage)
+ << attrT(_BuildBrowserInformation, tool.BuildBrowserInformation)
+ << attrE(_CharacterSet, tool.CharacterSet, /*ifNot*/ charSetNotSet)
+ << attrE(_ConfigurationType, tool.ConfigurationType)
+ << attrS(_DeleteExtensionsOnClean, tool.DeleteExtensionsOnClean)
+ << attrS(_ImportLibrary, tool.ImportLibrary)
+ << attrS(_IntermediateDirectory, tool.IntermediateDirectory)
+ << attrS(_PrimaryOutput, tool.PrimaryOutput)
+ << attrS(_ProgramDatabase, tool.ProgramDatabase)
+ << attrT(_RegisterOutput, tool.RegisterOutput)
+ << attrE(_UseOfATL, tool.UseOfATL, /*ifNot*/ useATLNotSet)
+ << attrE(_UseOfMfc, tool.UseOfMfc)
+ << attrT(_WholeProgramOptimization, tool.WholeProgramOptimization)
+ << tool.compiler
+ << tool.custom;
+ if (tool.ConfigurationType == typeStaticLibrary)
+ xml << tool.librarian;
+ else
+ xml << tool.linker;
+ xml << tool.idl
+ << tool.postBuild
+ << tool.preBuild
+ << tool.preLink
+ << tool.resource
+ << tool.deployment
+ << closetag(_Configuration);
+ return xml;
+}
+// VCFilter ---------------------------------------------------------
+VCFilter::VCFilter()
+ : ParseFiles(unset),
+ Config(0)
+{
+ useCustomBuildTool = false;
+ useCompilerTool = false;
+}
+
+void VCFilter::addFile(const QString& filename)
+{
+ Files += VCFilterFile(filename);
+}
+
+void VCFilter::addFile(const VCFilterFile& fileInfo)
+{
+ Files += VCFilterFile(fileInfo);
+}
+
+void VCFilter::addFiles(const QStringList& fileList)
+{
+ for (int i = 0; i < fileList.count(); ++i)
+ addFile(fileList.at(i));
+}
+
+void VCFilter::modifyPCHstage(QString str)
+{
+ bool autogenSourceFile = Project->autogenPrecompCPP;
+ bool pchThroughSourceFile = !Project->precompCPP.isEmpty();
+ bool isCFile = false;
+ for (QStringList::Iterator it = Option::c_ext.begin(); it != Option::c_ext.end(); ++it) {
+ if (str.endsWith(*it)) {
+ isCFile = true;
+ break;
+ }
+ }
+ bool isHFile = str.endsWith(".h") && (str == Project->precompH);
+ bool isCPPFile = pchThroughSourceFile && (str == Project->precompCPP);
+
+ if(!isCFile && !isHFile && !isCPPFile)
+ return;
+
+ if(isHFile && pchThroughSourceFile) {
+ if (autogenSourceFile) {
+ useCustomBuildTool = true;
+ QString toFile(Project->precompCPP);
+ CustomBuildTool.Description = "Generating precompiled header source file '" + toFile + "' ...";
+ CustomBuildTool.Outputs += toFile;
+
+ QStringList lines;
+ CustomBuildTool.CommandLine +=
+ "echo /*-------------------------------------------------------------------- >" + toFile;
+ lines << "* Precompiled header source file used by Visual Studio.NET to generate";
+ lines << "* the .pch file.";
+ lines << "*";
+ lines << "* Due to issues with the dependencies checker within the IDE, it";
+ lines << "* sometimes fails to recompile the PCH file, if we force the IDE to";
+ lines << "* create the PCH file directly from the header file.";
+ lines << "*";
+ lines << "* This file is auto-generated by qmake since no PRECOMPILED_SOURCE was";
+ lines << "* specified, and is used as the common stdafx.cpp. The file is only";
+ lines << "* generated when creating .vcproj project files, and is not used for";
+ lines << "* command line compilations by nmake.";
+ lines << "*";
+ lines << "* WARNING: All changes made in this file will be lost.";
+ lines << "--------------------------------------------------------------------*/";
+ lines << "#include \"" + Project->precompHFilename + "\"";
+ foreach(QString line, lines)
+ CustomBuildTool.CommandLine += "echo " + line + ">>" + toFile;
+ }
+ return;
+ }
+
+ useCompilerTool = true;
+ // Setup PCH options
+ CompilerTool.UsePrecompiledHeader = (isCFile ? pchNone : pchCreateUsingSpecific);
+ CompilerTool.PrecompiledHeaderThrough = (isCPPFile ? QString("$(INHERIT)") : QString("$(NOINHERIT)"));
+ CompilerTool.ForcedIncludeFiles = QStringList("$(NOINHERIT)");
+}
+
+bool VCFilter::addExtraCompiler(const VCFilterFile &info)
+{
+ const QStringList &extraCompilers = Project->extraCompilerSources.value(info.file);
+ if (extraCompilers.isEmpty())
+ return false;
+
+ QString inFile = info.file;
+
+ // is the extracompiler rule on a file with a built in compiler?
+ const QStringList &objectMappedFile = Project->extraCompilerOutputs[inFile];
+ bool hasBuiltIn = false;
+ if (!objectMappedFile.isEmpty()) {
+ hasBuiltIn = Project->hasBuiltinCompiler(objectMappedFile.at(0));
+// qDebug("*** Extra compiler file has object mapped file '%s' => '%s'", qPrintable(inFile), qPrintable(objectMappedFile.join(" ")));
+ }
+
+ CustomBuildTool.AdditionalDependencies.clear();
+ CustomBuildTool.CommandLine.clear();
+ CustomBuildTool.Description.clear();
+ CustomBuildTool.Outputs.clear();
+ CustomBuildTool.ToolPath.clear();
+ CustomBuildTool.ToolName = QLatin1String(_VCCustomBuildTool);
+
+ for (int x = 0; x < extraCompilers.count(); ++x) {
+ const QString &extraCompilerName = extraCompilers.at(x);
+
+ if (!Project->verifyExtraCompiler(extraCompilerName, inFile) && !hasBuiltIn)
+ continue;
+
+ // All information about the extra compiler
+ QString tmp_out = Project->project->first(extraCompilerName + ".output");
+ QString tmp_cmd = Project->project->variables()[extraCompilerName + ".commands"].join(" ");
+ QString tmp_cmd_name = Project->project->variables()[extraCompilerName + ".name"].join(" ");
+ QStringList tmp_dep = Project->project->variables()[extraCompilerName + ".depends"];
+ QString tmp_dep_cmd = Project->project->variables()[extraCompilerName + ".depend_command"].join(" ");
+ QStringList vars = Project->project->variables()[extraCompilerName + ".variables"];
+ QStringList configs = Project->project->variables()[extraCompilerName + ".CONFIG"];
+ bool combined = configs.indexOf("combine") != -1;
+
+ QString cmd, cmd_name, out;
+ QStringList deps, inputs;
+ // Variabel replacement of output name
+ out = Option::fixPathToTargetOS(
+ Project->replaceExtraCompilerVariables(tmp_out, inFile, QString()),
+ false);
+
+ // If file has built-in compiler, we've swapped the input and output of
+ // the command, as we in Visual Studio cannot have a Custom Buildstep on
+ // a file which uses a built-in compiler. We would in this case only get
+ // the result from the extra compiler. If 'hasBuiltIn' is true, we know
+ // that we're actually on the _output_file_ of the result, and we
+ // therefore swap inFile and out below, since the extra-compiler still
+ // must see it as the original way. If the result also has a built-in
+ // compiler, too bad..
+ if (hasBuiltIn) {
+ out = inFile;
+ inFile = objectMappedFile.at(0);
+ }
+
+ // Dependency for the output
+ if(!tmp_dep.isEmpty())
+ deps = tmp_dep;
+ if(!tmp_dep_cmd.isEmpty()) {
+ // Execute dependency command, and add every line as a dep
+ char buff[256];
+ QString dep_cmd = Project->replaceExtraCompilerVariables(tmp_dep_cmd,
+ Option::fixPathToLocalOS(inFile, true, false),
+ out);
+ if(Project->canExecute(dep_cmd)) {
+ if(FILE *proc = QT_POPEN(dep_cmd.toLatin1().constData(), "r")) {
+ QString indeps;
+ while(!feof(proc)) {
+ int read_in = (int)fread(buff, 1, 255, proc);
+ if(!read_in)
+ break;
+ indeps += QByteArray(buff, read_in);
+ }
+ QT_PCLOSE(proc);
+ if(!indeps.isEmpty()) {
+ QStringList extradeps = indeps.split(QLatin1Char('\n'));
+ for (int i = 0; i < extradeps.count(); ++i) {
+ QString dd = extradeps.at(i).simplified();
+ if (!dd.isEmpty())
+ deps += Project->fileFixify(dd);
+ }
+ }
+ }
+ }
+ }
+ for (int i = 0; i < deps.count(); ++i)
+ deps[i] = Option::fixPathToTargetOS(
+ Project->replaceExtraCompilerVariables(deps.at(i), inFile, out),
+ false).trimmed();
+ // Command for file
+ if (combined) {
+ // Add dependencies for each file
+ QStringList tmp_in = Project->project->variables()[extraCompilerName + ".input"];
+ for (int a = 0; a < tmp_in.count(); ++a) {
+ const QStringList &files = Project->project->variables()[tmp_in.at(a)];
+ for (int b = 0; b < files.count(); ++b) {
+ deps += Project->findDependencies(files.at(b));
+ inputs += Option::fixPathToTargetOS(files.at(b), false);
+ }
+ }
+ deps += inputs; // input files themselves too..
+
+ // Replace variables for command w/all input files
+ // ### join gives path issues with directories containing spaces!
+ cmd = Project->replaceExtraCompilerVariables(tmp_cmd,
+ inputs.join(" "),
+ out);
+ } else {
+ deps += inFile; // input file itself too..
+ cmd = Project->replaceExtraCompilerVariables(tmp_cmd,
+ inFile,
+ out);
+ }
+ // Name for command
+ if(!tmp_cmd_name.isEmpty()) {
+ cmd_name = Project->replaceExtraCompilerVariables(tmp_cmd_name, inFile, out);
+ } else {
+ int space = cmd.indexOf(' ');
+ if(space != -1)
+ cmd_name = cmd.left(space);
+ else
+ cmd_name = cmd;
+ if((cmd_name[0] == '\'' || cmd_name[0] == '"') &&
+ cmd_name[0] == cmd_name[cmd_name.length()-1])
+ cmd_name = cmd_name.mid(1,cmd_name.length()-2);
+ }
+
+ // Fixify paths
+ for (int i = 0; i < deps.count(); ++i)
+ deps[i] = Option::fixPathToTargetOS(deps[i], false);
+
+
+ // Output in info.additionalFile -----------
+ if (!CustomBuildTool.Description.isEmpty())
+ CustomBuildTool.Description += " & ";
+ CustomBuildTool.Description += cmd_name;
+ CustomBuildTool.CommandLine += cmd.trimmed().split("\n", QString::SkipEmptyParts);
+ int space = cmd.indexOf(' ');
+ QFileInfo finf(cmd.left(space));
+ if (CustomBuildTool.ToolPath.isEmpty())
+ CustomBuildTool.ToolPath += Option::fixPathToTargetOS(finf.path());
+ CustomBuildTool.Outputs += out;
+
+ deps += CustomBuildTool.AdditionalDependencies;
+ deps += cmd.left(cmd.indexOf(' '));
+ // Make sure that all deps are only once
+ QMap<QString, bool> uniqDeps;
+ for (int c = 0; c < deps.count(); ++c) {
+ QString aDep = deps.at(c).trimmed();
+ if (!aDep.isEmpty())
+ uniqDeps[aDep] = false;
+ }
+ CustomBuildTool.AdditionalDependencies = uniqDeps.keys();
+ }
+
+ // Ensure that none of the output files are also dependencies. Or else, the custom buildstep
+ // will be rebuild every time, even if nothing has changed.
+ foreach(QString output, CustomBuildTool.Outputs) {
+ CustomBuildTool.AdditionalDependencies.removeAll(output);
+ }
+
+ useCustomBuildTool = !CustomBuildTool.CommandLine.isEmpty();
+ return useCustomBuildTool;
+}
+
+void VCFilter::outputFileConfig(XmlOutput &xml, const QString &filename)
+{
+ // Clearing each filter tool
+ useCustomBuildTool = false;
+ useCompilerTool = false;
+ CustomBuildTool = VCCustomBuildTool();
+ CompilerTool = VCCLCompilerTool();
+
+ // Unset some default options
+ CompilerTool.BufferSecurityCheck = unset;
+ CompilerTool.DebugInformationFormat = debugUnknown;
+ CompilerTool.ExceptionHandling = ehDefault;
+ CompilerTool.GeneratePreprocessedFile = preprocessUnknown;
+ CompilerTool.Optimization = optimizeDefault;
+ CompilerTool.ProgramDataBaseFileName.clear();
+ CompilerTool.RuntimeLibrary = rtUnknown;
+ CompilerTool.WarningLevel = warningLevelUnknown;
+ CompilerTool.config = Config;
+
+ bool inBuild = false;
+ VCFilterFile info;
+ for (int i = 0; i < Files.count(); ++i) {
+ if (Files.at(i).file == filename) {
+ info = Files.at(i);
+ inBuild = true;
+ }
+ }
+ inBuild &= !info.excludeFromBuild;
+
+ if (inBuild) {
+ addExtraCompiler(info);
+ if(Project->usePCH)
+ modifyPCHstage(info.file);
+ } else {
+ // Excluded files uses an empty compiler stage
+ if(info.excludeFromBuild)
+ useCompilerTool = true;
+ }
+
+ // Actual XML output ----------------------------------
+ if(useCustomBuildTool || useCompilerTool || !inBuild) {
+ xml << tag(_FileConfiguration)
+ << attr(_Name, (*Config).Name)
+ << (!inBuild ? attrS(_ExcludedFromBuild, "true") : noxml());
+ if (useCustomBuildTool)
+ xml << CustomBuildTool;
+ if (useCompilerTool)
+ xml << CompilerTool;
+ xml << closetag(_FileConfiguration);
+ }
+}
+
+XmlOutput &operator<<(XmlOutput &xml, VCFilter &tool)
+{
+ if(!tool.Files.count())
+ return xml;
+
+ if (!tool.Name.isEmpty()) {
+ xml << tag(_Filter)
+ << attrS(_Name, tool.Name)
+ << attrS(_Filter, tool.Filter)
+ << attrS(_UniqueIdentifier, tool.Guid)
+ << attrT(_ParseFiles, tool.ParseFiles);
+ }
+ for (int i = 0; i < tool.Files.count(); ++i) {
+ const VCFilterFile &info = tool.Files.at(i);
+ xml << tag(_File)
+ << attrS(_RelativePath, Option::fixPathToLocalOS(info.file))
+ << data(); // In case no custom builds, to avoid "/>" endings
+ tool.outputFileConfig(xml, tool.Files.at(i).file);
+ xml << closetag(_File);
+ }
+ if (!tool.Name.isEmpty())
+ xml << closetag(_Filter);
+ return xml;
+}
+
+// VCProjectSingleConfig --------------------------------------------
+VCFilter nullFilter;
+VCFilter& VCProjectSingleConfig::filterForExtraCompiler(const QString &compilerName)
+{
+ for (int i = 0; i < ExtraCompilersFiles.count(); ++i)
+ if (ExtraCompilersFiles.at(i).Name == compilerName)
+ return ExtraCompilersFiles[i];
+ return nullFilter;
+}
+
+
+XmlOutput &operator<<(XmlOutput &xml, const VCProjectSingleConfig &tool)
+{
+ xml << decl("1.0", "Windows-1252")
+ << tag(_VisualStudioProject)
+ << attrS(_ProjectType, "Visual C++")
+ << attrS(_Version, tool.Version)
+ << attrS(_Name, tool.Name)
+ << attrS(_ProjectGUID, tool.ProjectGUID)
+ << attrS(_Keyword, tool.Keyword)
+ << attrS(_SccProjectName, tool.SccProjectName)
+ << attrS(_SccLocalPath, tool.SccLocalPath)
+ << tag(_Platforms)
+ << tag(_Platform)
+ << attrS(_Name, tool.PlatformName)
+ << closetag(_Platforms)
+ << tag(_Configurations)
+ << tool.Configuration;
+ xml << closetag(_Configurations)
+ << tag(_Files);
+ // Add this configuration into a multi-config project, since that's where we have the flat/tree
+ // XML output functionality
+ VCProject tempProj;
+ tempProj.SingleProjects += tool;
+ tempProj.outputFilter(xml, "Sources");
+ tempProj.outputFilter(xml, "Headers");
+ tempProj.outputFilter(xml, "GeneratedFiles");
+ tempProj.outputFilter(xml, "LexYaccFiles");
+ tempProj.outputFilter(xml, "TranslationFiles");
+ tempProj.outputFilter(xml, "FormFiles");
+ tempProj.outputFilter(xml, "ResourceFiles");
+ for (int x = 0; x < tempProj.ExtraCompilers.count(); ++x) {
+ tempProj.outputFilter(xml, tempProj.ExtraCompilers.at(x));
+ }
+ tempProj.outputFilter(xml, "RootFiles");
+ xml << closetag(_Files)
+ << tag(_Globals)
+ << data(); // No "/>" end tag
+ return xml;
+}
+
+
+// Tree file generation ---------------------------------------------
+void TreeNode::generateXML(XmlOutput &xml, const QString &tagName, VCProject &tool, const QString &filter) {
+ if (children.size()) {
+ // Filter
+ ChildrenMap::ConstIterator it, end = children.constEnd();
+ if (!tagName.isEmpty()) {
+ xml << tag("Filter")
+ << attr("Name", tagName)
+ << attr("Filter", "");
+ }
+ // First round, do nested filters
+ for (it = children.constBegin(); it != end; ++it)
+ if ((*it)->children.size())
+ (*it)->generateXML(xml, it.key(), tool, filter);
+ // Second round, do leafs
+ for (it = children.constBegin(); it != end; ++it)
+ if (!(*it)->children.size())
+ (*it)->generateXML(xml, it.key(), tool, filter);
+
+ if (!tagName.isEmpty())
+ xml << closetag("Filter");
+ } else {
+ // Leaf
+ tool.outputFileConfigs(xml, info, filter);
+ }
+}
+
+
+// Flat file generation ---------------------------------------------
+void FlatNode::generateXML(XmlOutput &xml, const QString &/*tagName*/, VCProject &tool, const QString &filter) {
+ if (children.size()) {
+ ChildrenMapFlat::ConstIterator it = children.constBegin();
+ ChildrenMapFlat::ConstIterator end = children.constEnd();
+ for (; it != end; ++it) {
+ tool.outputFileConfigs(xml, (*it), filter);
+ }
+ }
+}
+
+
+// VCProject --------------------------------------------------------
+// Output all configurations (by filtername) for a file (by info)
+// A filters config output is in VCFilter.outputFileConfig()
+void VCProject::outputFileConfigs(XmlOutput &xml,
+// VCProjectSingleConfig::FilterTypes type
+ const VCFilterFile &info,
+ const QString &filtername)
+{
+ xml << tag(_File)
+ << attrS(_RelativePath, Option::fixPathToLocalOS(info.file));
+ for (int i = 0; i < SingleProjects.count(); ++i) {
+ VCFilter filter;
+ if (filtername == "RootFiles") {
+ filter = SingleProjects.at(i).RootFiles;
+ } else if (filtername == "Sources") {
+ filter = SingleProjects.at(i).SourceFiles;
+ } else if (filtername == "Headers") {
+ filter = SingleProjects.at(i).HeaderFiles;
+ } else if (filtername == "GeneratedFiles") {
+ filter = SingleProjects.at(i).GeneratedFiles;
+ } else if (filtername == "LexYaccFiles") {
+ filter = SingleProjects.at(i).LexYaccFiles;
+ } else if (filtername == "TranslationFiles") {
+ filter = SingleProjects.at(i).TranslationFiles;
+ } else if (filtername == "FormFiles") {
+ filter = SingleProjects.at(i).FormFiles;
+ } else if (filtername == "ResourceFiles") {
+ filter = SingleProjects.at(i).ResourceFiles;
+ } else {
+ // ExtraCompilers
+ filter = SingleProjects[i].filterForExtraCompiler(filtername);
+ }
+
+ if (filter.Config) // only if the filter is not empty
+ filter.outputFileConfig(xml, info.file);
+ }
+ xml << closetag(_File);
+}
+
+// outputs a given filter for all existing configurations of a project
+void VCProject::outputFilter(XmlOutput &xml,
+// VCProjectSingleConfig::FilterTypes type
+ const QString &filtername)
+{
+ Node *root;
+ if (SingleProjects.at(0).flat_files)
+ root = new FlatNode;
+ else
+ root = new TreeNode;
+
+ QString name, extfilter, guid;
+ triState parse;
+
+ for (int i = 0; i < SingleProjects.count(); ++i) {
+ VCFilter filter;
+ if (filtername == "RootFiles") {
+ filter = SingleProjects.at(i).RootFiles;
+ } else if (filtername == "Sources") {
+ filter = SingleProjects.at(i).SourceFiles;
+ } else if (filtername == "Headers") {
+ filter = SingleProjects.at(i).HeaderFiles;
+ } else if (filtername == "GeneratedFiles") {
+ filter = SingleProjects.at(i).GeneratedFiles;
+ } else if (filtername == "LexYaccFiles") {
+ filter = SingleProjects.at(i).LexYaccFiles;
+ } else if (filtername == "TranslationFiles") {
+ filter = SingleProjects.at(i).TranslationFiles;
+ } else if (filtername == "FormFiles") {
+ filter = SingleProjects.at(i).FormFiles;
+ } else if (filtername == "ResourceFiles") {
+ filter = SingleProjects.at(i).ResourceFiles;
+ } else {
+ // ExtraCompilers
+ filter = SingleProjects[i].filterForExtraCompiler(filtername);
+ }
+
+ // Merge all files in this filter to root tree
+ for (int x = 0; x < filter.Files.count(); ++x)
+ root->addElement(filter.Files.at(x));
+
+ // Save filter setting from first filter. Next filters
+ // may differ but we cannot handle that. (ex. extfilter)
+ if (name.isEmpty()) {
+ name = filter.Name;
+ extfilter = filter.Filter;
+ parse = filter.ParseFiles;
+ guid = filter.Guid;
+ }
+ }
+
+ if (!root->hasElements())
+ return;
+
+ // Actual XML output ----------------------------------
+ if (!name.isEmpty()) {
+ xml << tag(_Filter)
+ << attrS(_Name, name)
+ << attrS(_Filter, extfilter)
+ << attrS(_UniqueIdentifier, guid)
+ << attrT(_ParseFiles, parse);
+ }
+ root->generateXML(xml, "", *this, filtername); // output root tree
+ if (!name.isEmpty())
+ xml << closetag(_Filter);
+}
+
+XmlOutput &operator<<(XmlOutput &xml, VCProject &tool)
+{
+ if (tool.SingleProjects.count() == 0) {
+ warn_msg(WarnLogic, "Generator: .NET: no single project in merge project, no output");
+ return xml;
+ }
+
+ xml << decl("1.0", "Windows-1252")
+ << tag(_VisualStudioProject)
+ << attrS(_ProjectType, "Visual C++")
+ << attrS(_Version, tool.Version)
+ << attrS(_Name, tool.Name)
+ << attrS(_ProjectGUID, tool.ProjectGUID)
+ << attrS(_Keyword, tool.Keyword)
+ << attrS(_SccProjectName, tool.SccProjectName)
+ << attrS(_SccLocalPath, tool.SccLocalPath)
+ << tag(_Platforms)
+ << tag(_Platform)
+ << attrS(_Name, tool.PlatformName)
+ << closetag(_Platforms)
+ << tag(_Configurations);
+ // Output each configuration
+ for (int i = 0; i < tool.SingleProjects.count(); ++i)
+ xml << tool.SingleProjects.at(i).Configuration;
+ xml << closetag(_Configurations)
+ << tag(_Files);
+ tool.outputFilter(xml, "Sources");
+ tool.outputFilter(xml, "Headers");
+ tool.outputFilter(xml, "GeneratedFiles");
+ tool.outputFilter(xml, "LexYaccFiles");
+ tool.outputFilter(xml, "TranslationFiles");
+ tool.outputFilter(xml, "FormFiles");
+ tool.outputFilter(xml, "ResourceFiles");
+ for (int x = 0; x < tool.ExtraCompilers.count(); ++x) {
+ tool.outputFilter(xml, tool.ExtraCompilers.at(x));
+ }
+ tool.outputFilter(xml, "RootFiles");
+ xml << closetag(_Files)
+ << tag(_Globals)
+ << data(); // No "/>" end tag
+ return xml;
+}
+
+QT_END_NAMESPACE
diff --git a/qmake/generators/win32/msvc_objectmodel.h b/qmake/generators/win32/msvc_objectmodel.h
new file mode 100644
index 0000000..e3f56f6
--- /dev/null
+++ b/qmake/generators/win32/msvc_objectmodel.h
@@ -0,0 +1,1078 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef MSVC_OBJECTMODEL_H
+#define MSVC_OBJECTMODEL_H
+
+#include "project.h"
+#include "xmloutput.h"
+#include <qatomic.h>
+#include <qlist.h>
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qmap.h>
+#include <qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+enum DotNET {
+ NETUnknown = 0,
+ NET2002 = 0x70,
+ NET2003 = 0x71,
+ NET2005 = 0x80,
+ NET2008 = 0x90
+};
+
+/*
+ This Object model is of course VERY simplyfied,
+ and does not actually follow the original MSVC
+ object model. However, it fulfilles the basic
+ needs for qmake
+*/
+
+/*
+ If a triState value is 'unset' then the
+ corresponding property is not in the output,
+ forcing the tool to utilize default values.
+ False/True values will be in the output...
+*/
+enum customBuildCheck {
+ none,
+ mocSrc,
+ mocHdr,
+ lexyacc
+};
+enum triState {
+ unset = -1,
+ _False = 0,
+ _True = 1
+};
+enum addressAwarenessType {
+ addrAwareDefault,
+ addrAwareNoLarge,
+ addrAwareLarge
+};
+enum asmListingOption {
+ asmListingNone,
+ asmListingAssemblyOnly,
+ asmListingAsmMachineSrc,
+ asmListingAsmMachine,
+ asmListingAsmSrc
+};
+enum basicRuntimeCheckOption {
+ runtimeBasicCheckNone,
+ runtimeCheckStackFrame,
+ runtimeCheckUninitVariables,
+ runtimeBasicCheckAll
+};
+enum browseInfoOption {
+ brInfoNone,
+ brAllInfo,
+ brNoLocalSymbols
+};
+enum callingConventionOption {
+ callConventionDefault = -1,
+ callConventionCDecl,
+ callConventionFastCall,
+ callConventionStdCall
+};
+enum charSet {
+ charSetNotSet,
+ charSetUnicode,
+ charSetMBCS
+};
+enum compileAsManagedOptions {
+ managedDefault = -1, // Was: noAssembly
+ managedAssembly = 1,
+ managedAssemblyPure = 2, // Old was: Assembly
+ managedAssemblySafe = 3,
+ managedAssemblyOldSyntax = 4
+};
+enum CompileAsOptions{
+ compileAsDefault,
+ compileAsC,
+ compileAsCPlusPlus
+};
+enum ConfigurationTypes {
+ typeUnknown = 0,
+ typeApplication = 1,
+ typeDynamicLibrary = 2,
+ typeStaticLibrary = 4,
+ typeGeneric = 10
+};
+enum debugOption {
+ debugUnknown = -1,
+ debugDisabled,
+ debugOldStyleInfo,
+ debugLineInfoOnly,
+ debugEnabled,
+ debugEditAndContinue
+};
+enum eAppProtectionOption {
+ eAppProtectUnchanged,
+ eAppProtectLow,
+ eAppProtectMedium,
+ eAppProtectHigh
+};
+enum enhancedInstructionSetOption {
+ archNotSet = 0,
+ archSSE = 1,
+ archSSE2 = 2
+};
+enum exceptionHandling {
+ ehDefault = -1,
+ ehNone = 0,
+ ehNoSEH = 1,
+ ehSEH = 2
+};
+enum enumResourceLangID {
+ rcUseDefault = 0,
+ rcAfrikaans = 1078,
+ rcAlbanian = 1052,
+ rcArabicAlgeria = 5121,
+ rcArabicBahrain = 15361,
+ rcArabicEgypt = 3073,
+ rcArabicIraq = 2049,
+ rcArabicJordan = 11265,
+ rcArabicKuwait = 13313,
+ rcArabicLebanon = 12289,
+ rcArabicLibya = 4097,
+ rcArabicMorocco = 6145,
+ rcArabicOman = 8193,
+ rcArabicQatar = 16385,
+ rcArabicSaudi = 1025,
+ rcArabicSyria = 10241,
+ rcArabicTunisia = 7169,
+ rcArabicUnitedArabEmirates = 14337,
+ rcArabicYemen = 9217,
+ rcBasque = 1069,
+ rcBulgarian = 1026,
+ rcByelorussian = 1059,
+ rcCatalan = 1027,
+ rcChineseHongKong = 3076,
+ rcChinesePRC = 2052,
+ rcChineseSingapore = 4100,
+ rcChineseTaiwan = 1028,
+ rcCroatian = 1050,
+ rcCzech = 1029,
+ rcDanish = 1030,
+ rcDutchBelgium = 2067,
+ rcDutchStandard = 1043,
+ rcEnglishAustralia = 3081,
+ rcEnglishBritain = 2057,
+ rcEnglishCanada = 4105,
+ RcEnglishCaribbean = 9225,
+ rcEnglishIreland = 6153,
+ rcEnglishJamaica = 8201,
+ rcEnglishNewZealand = 5129,
+ rcEnglishSouthAfrica = 7177,
+ rcEnglishUS = 1033,
+ rcEstonian = 1061,
+ rcFarsi = 1065,
+ rcFinnish = 1035,
+ rcFrenchBelgium = 2060,
+ rcFrenchCanada = 3084,
+ rcFrenchLuxembourg = 5132,
+ rcFrenchStandard = 1036,
+ rcFrenchSwitzerland = 4108,
+ rcGermanAustria = 3079,
+ rcGermanLichtenstein = 5127,
+ rcGermanLuxembourg = 4103,
+ rcGermanStandard = 1031,
+ rcGermanSwitzerland = 2055,
+ rcGreek = 1032,
+ rcHebrew = 1037,
+ rcHungarian = 1038,
+ rcIcelandic = 1039,
+ rcIndonesian = 1057,
+ rcItalianStandard = 1040,
+ rcItalianSwitzerland = 2064,
+ rcJapanese = 1041,
+ rcKorean = 1042,
+ rcKoreanJohab = 2066,
+ rcLatvian = 1062,
+ rcLithuanian = 1063,
+ rcNorwegianBokmal = 1044,
+ rcNorwegianNynorsk = 2068,
+ rcPolish = 1045,
+ rcPortugueseBrazilian = 1046,
+ rcPortugueseStandard = 2070,
+ rcRomanian = 1048,
+ rcRussian = 1049,
+ rcSerbian = 2074,
+ rcSlovak = 1051,
+ rcSpanishArgentina = 11274,
+ rcSpanishBolivia = 16394,
+ rcSpanishChile = 13322,
+ rcSpanishColombia = 9226,
+ rcSpanishCostaRica = 5130,
+ rcSpanishDominicanRepublic = 7178,
+ rcSpanishEcuador = 12298,
+ rcSpanishGuatemala = 4106,
+ rcSpanishMexico = 2058,
+ rcSpanishModern = 3082,
+ rcSpanishPanama = 6154,
+ rcSpanishParaguay = 15370,
+ rcSpanishPeru = 10250,
+ rcSpanishTraditional = 1034,
+ rcSpanishUruguay = 14346,
+ rcSpanishVenezuela = 8202,
+ rcSwedish = 1053,
+ rcThai = 1054,
+ rcTurkish = 1055,
+ rcUkrainian = 1058,
+ rcUrdu = 1056
+};
+enum enumSccEvent {
+ eProjectInScc,
+ ePreDirtyNotification
+};
+enum favorSizeOrSpeedOption {
+ favorNone,
+ favorSpeed,
+ favorSize
+};
+enum floatingPointModel {
+ floatingPointNotSet = -1,
+ floatingPointPrecise,
+ floatingPointStrict,
+ floatingPointFast
+};
+enum genProxyLanguage {
+ genProxyNative,
+ genProxyManaged
+};
+enum inlineExpansionOption {
+ expandDisable,
+ expandOnlyInline,
+ expandAnySuitable,
+ expandDefault // Not useful number, but stops the output
+};
+enum linkIncrementalType {
+ linkIncrementalDefault,
+ linkIncrementalNo,
+ linkIncrementalYes
+};
+enum linkProgressOption {
+ linkProgressNotSet,
+ linkProgressAll,
+ linkProgressLibs
+};
+enum machineTypeOption {
+ machineNotSet,
+ machineX86
+};
+enum midlCharOption {
+ midlCharUnsigned,
+ midlCharSigned,
+ midlCharAscii7
+};
+enum midlErrorCheckOption {
+ midlEnableCustom,
+ midlDisableAll,
+ midlEnableAll
+};
+enum midlStructMemberAlignOption {
+ midlAlignNotSet,
+ midlAlignSingleByte,
+ midlAlignTwoBytes,
+ midlAlignFourBytes,
+ midlAlignEightBytes,
+ midlAlignSixteenBytes
+};
+enum midlTargetEnvironment {
+ midlTargetNotSet,
+ midlTargetWin32,
+ midlTargetWin64
+};
+enum midlWarningLevelOption {
+ midlWarningLevel_0,
+ midlWarningLevel_1,
+ midlWarningLevel_2,
+ midlWarningLevel_3,
+ midlWarningLevel_4
+};
+enum optFoldingType {
+ optFoldingDefault,
+ optNoFolding,
+ optFolding
+};
+enum optimizeOption {
+ optimizeDisabled,
+ optimizeMinSpace,
+ optimizeMaxSpeed,
+ optimizeFull,
+ optimizeCustom,
+ optimizeDefault // Not useful number, but stops the output
+};
+enum optRefType {
+ optReferencesDefault,
+ optNoReferences,
+ optReferences
+};
+enum optWin98Type {
+ optWin98Default,
+ optWin98No,
+ optWin98Yes
+};
+enum optLinkTimeCodeGenType {
+ optLTCGDefault,
+ optLTCGEnabled,
+ optLTCGInstrument,
+ optLTCGOptimize,
+ optLTCGUpdate
+};
+enum pchOption {
+ pchNone,
+ pchCreateUsingSpecific,
+ pchGenerateAuto,
+ pchUseUsingSpecific
+};
+enum preprocessOption {
+ preprocessUnknown = -1,
+ preprocessNo,
+ preprocessYes,
+ preprocessNoLineNumbers
+};
+enum ProcessorOptimizeOption {
+ procOptimizeBlended, //GB
+ procOptimizePentium, //G5
+ procOptimizePentiumProAndAbove, //G6
+ procOptimizePentium4AndAbove //G7
+};
+enum RegisterDeployOption {
+ registerNo = 0,
+ registerYes
+};
+enum RemoteDebuggerType {
+ DbgLocal,
+ DbgRemote,
+ DbgRemoteTCPIP
+};
+enum runtimeLibraryOption {
+ rtUnknown = -1,
+ rtMultiThreaded,
+ rtMultiThreadedDebug,
+ rtMultiThreadedDLL,
+ rtMultiThreadedDebugDLL,
+ rtSingleThreaded,
+ rtSingleThreadedDebug
+};
+enum structMemberAlignOption {
+ alignNotSet,
+ alignSingleByte,
+ alignTwoBytes,
+ alignFourBytes,
+ alignEightBytes,
+ alignSixteenBytes
+};
+enum subSystemOption {
+ subSystemNotSet,
+ subSystemConsole,
+ subSystemWindows
+};
+enum termSvrAwarenessType {
+ termSvrAwareDefault,
+ termSvrAwareNo,
+ termSvrAwareYes
+};
+enum toolSetType {
+ toolSetUtility,
+ toolSetMakefile,
+ toolSetLinker,
+ toolSetLibrarian,
+ toolSetAll
+};
+enum TypeOfDebugger {
+ DbgNativeOnly,
+ DbgManagedOnly,
+ DbgMixed,
+ DbgAuto
+};
+enum useOfATL {
+ useATLNotSet,
+ useATLStatic,
+ useATLDynamic
+};
+enum useOfMfc {
+ useMfcStdWin,
+ useMfcStatic,
+ useMfcDynamic
+};
+enum useOfArchitecture {
+ archUnknown = -1,
+ archArmv4,
+ archArmv5,
+ archArmv4T,
+ archArmv5T,
+ archMips1 = 0,
+ archMips2 = 1,
+ archMips3 = 2,
+ archMips4 = 3,
+ archMips5 = 4,
+ archMips16 = 5,
+ archMips32 = 6,
+ archMips64 = 7
+};
+enum warningLevelOption {
+ warningLevelUnknown = -1,
+ warningLevel_0,
+ warningLevel_1,
+ warningLevel_2,
+ warningLevel_3,
+ warningLevel_4
+};
+
+
+class VCToolBase {
+protected:
+ // Functions
+ VCToolBase(){};
+ virtual ~VCToolBase(){}
+ virtual bool parseOption(const char* option) = 0;
+public:
+ void parseOptions(QStringList& options) {
+ for (QStringList::ConstIterator it=options.begin(); (it!=options.end()); it++)
+ parseOption((*it).toLatin1());
+ }
+};
+
+class VCConfiguration;
+class VCProject;
+
+class VCCLCompilerTool : public VCToolBase
+{
+public:
+ // Functions
+ VCCLCompilerTool();
+ virtual ~VCCLCompilerTool(){}
+ bool parseOption(const char* option);
+
+ // Variables
+ QStringList AdditionalIncludeDirectories;
+ QStringList AdditionalOptions;
+ QStringList AdditionalUsingDirectories;
+ QString AssemblerListingLocation;
+ asmListingOption AssemblerOutput;
+ basicRuntimeCheckOption BasicRuntimeChecks;
+ browseInfoOption BrowseInformation;
+ QString BrowseInformationFile;
+ triState BufferSecurityCheck;
+ callingConventionOption CallingConvention;
+ CompileAsOptions CompileAs;
+ compileAsManagedOptions CompileAsManaged;
+ triState CompileOnly;
+ debugOption DebugInformationFormat;
+ triState DefaultCharIsUnsigned;
+ triState Detect64BitPortabilityProblems;
+ triState DisableLanguageExtensions;
+ QStringList DisableSpecificWarnings;
+ enhancedInstructionSetOption EnableEnhancedInstructionSet;
+ triState EnableFiberSafeOptimizations;
+ triState EnableFunctionLevelLinking;
+ triState EnableIntrinsicFunctions;
+ exceptionHandling ExceptionHandling;
+ triState ExpandAttributedSource;
+ favorSizeOrSpeedOption FavorSizeOrSpeed;
+ floatingPointModel FloatingPointModel;
+ triState FloatingPointExceptions;
+ triState ForceConformanceInForLoopScope;
+ QStringList ForcedIncludeFiles;
+ QStringList ForcedUsingFiles;
+ preprocessOption GeneratePreprocessedFile;
+ triState GlobalOptimizations;
+ triState IgnoreStandardIncludePath;
+ triState ImproveFloatingPointConsistency;
+ inlineExpansionOption InlineFunctionExpansion;
+ triState KeepComments;
+ triState MinimalRebuild;
+ QString ObjectFile;
+ triState OmitFramePointers;
+ triState OpenMP;
+ optimizeOption Optimization;
+ ProcessorOptimizeOption OptimizeForProcessor;
+ triState OptimizeForWindowsApplication;
+ QString OutputFile;
+ QString PrecompiledHeaderFile;
+ QString PrecompiledHeaderThrough;
+ QStringList PreprocessorDefinitions;
+ QString ProgramDataBaseFileName;
+ runtimeLibraryOption RuntimeLibrary;
+ triState RuntimeTypeInfo;
+ triState ShowIncludes;
+ triState SmallerTypeCheck;
+ triState StringPooling;
+ structMemberAlignOption StructMemberAlignment;
+ triState SuppressStartupBanner;
+ triState TreatWChar_tAsBuiltInType;
+ triState TurnOffAssemblyGeneration;
+ triState UndefineAllPreprocessorDefinitions;
+ QStringList UndefinePreprocessorDefinitions;
+ pchOption UsePrecompiledHeader;
+ triState WarnAsError;
+ warningLevelOption WarningLevel;
+ triState WholeProgramOptimization;
+ useOfArchitecture CompileForArchitecture;
+ triState InterworkCalls;
+ VCConfiguration* config;
+};
+
+class VCLinkerTool : public VCToolBase
+{
+public:
+ // Functions
+ VCLinkerTool();
+ virtual ~VCLinkerTool(){}
+ bool parseOption(const char* option);
+
+ // Variables
+ QStringList AdditionalDependencies;
+ QStringList AdditionalLibraryDirectories;
+ QStringList AdditionalOptions;
+ QStringList AddModuleNamesToAssembly;
+ QString BaseAddress;
+ QStringList DelayLoadDLLs;
+ optFoldingType EnableCOMDATFolding;
+ QString EntryPointSymbol;
+ QStringList ForceSymbolReferences;
+ QString FunctionOrder;
+ triState GenerateDebugInformation;
+ triState GenerateMapFile;
+ qlonglong HeapCommitSize;
+ qlonglong HeapReserveSize;
+ triState IgnoreAllDefaultLibraries;
+ QStringList IgnoreDefaultLibraryNames;
+ triState IgnoreEmbeddedIDL;
+ triState IgnoreImportLibrary;
+ QString ImportLibrary;
+ addressAwarenessType LargeAddressAware;
+ triState LinkDLL;
+ linkIncrementalType LinkIncremental;
+ optLinkTimeCodeGenType LinkTimeCodeGeneration;
+ QString LinkToManagedResourceFile;
+ triState MapExports;
+ QString MapFileName;
+ triState MapLines;
+ QString MergedIDLBaseFileName;
+ QString MergeSections; // Should be list?
+ QString MidlCommandFile;
+ QString ModuleDefinitionFile; // Should be list?
+ optWin98Type OptimizeForWindows98;
+ optRefType OptimizeReferences;
+ QString OutputFile;
+ QString ProgramDatabaseFile;
+ triState RegisterOutput;
+ triState ResourceOnlyDLL;
+ triState SetChecksum;
+ linkProgressOption ShowProgress;
+ qlonglong StackCommitSize;
+ qlonglong StackReserveSize;
+ QString StripPrivateSymbols; // Should be list?
+ subSystemOption SubSystem;
+ triState SupportUnloadOfDelayLoadedDLL;
+ triState SuppressStartupBanner;
+ triState SwapRunFromCD;
+ triState SwapRunFromNet;
+ machineTypeOption TargetMachine;
+ termSvrAwarenessType TerminalServerAware;
+ triState TurnOffAssemblyGeneration;
+ QString TypeLibraryFile;
+ qlonglong TypeLibraryResourceID;
+ QString Version;
+ VCConfiguration* config;
+};
+
+class VCMIDLTool : public VCToolBase
+{
+public:
+ // Functions
+ VCMIDLTool();
+ virtual ~VCMIDLTool(){}
+ bool parseOption(const char* option);
+
+ // Variables
+ QStringList AdditionalIncludeDirectories;
+ QStringList AdditionalOptions;
+ QStringList CPreprocessOptions;
+ midlCharOption DefaultCharType;
+ QString DLLDataFileName; // Should be list?
+ midlErrorCheckOption EnableErrorChecks;
+ triState ErrorCheckAllocations;
+ triState ErrorCheckBounds;
+ triState ErrorCheckEnumRange;
+ triState ErrorCheckRefPointers;
+ triState ErrorCheckStubData;
+ QStringList FullIncludePath;
+ triState GenerateStublessProxies;
+ triState GenerateTypeLibrary;
+ QString HeaderFileName;
+ triState IgnoreStandardIncludePath;
+ QString InterfaceIdentifierFileName;
+ triState MkTypLibCompatible;
+ QString OutputDirectory;
+ QStringList PreprocessorDefinitions;
+ QString ProxyFileName;
+ QString RedirectOutputAndErrors;
+ midlStructMemberAlignOption StructMemberAlignment;
+ triState SuppressStartupBanner;
+ midlTargetEnvironment TargetEnvironment;
+ QString TypeLibraryName;
+ QStringList UndefinePreprocessorDefinitions;
+ triState ValidateParameters;
+ triState WarnAsError;
+ midlWarningLevelOption WarningLevel;
+ VCConfiguration* config;
+};
+
+class VCLibrarianTool : public VCToolBase
+{
+public:
+ // Functions
+ VCLibrarianTool();
+ virtual ~VCLibrarianTool(){}
+ bool parseOption(const char*){ return false; };
+
+ // Variables
+ QStringList AdditionalDependencies;
+ QStringList AdditionalLibraryDirectories;
+ QStringList AdditionalOptions;
+ QStringList ExportNamedFunctions;
+ QStringList ForceSymbolReferences;
+ triState IgnoreAllDefaultLibraries;
+ QStringList IgnoreDefaultLibraryNames;
+ QString ModuleDefinitionFile;
+ QString OutputFile;
+ triState SuppressStartupBanner;
+};
+
+class VCCustomBuildTool : public VCToolBase
+{
+public:
+ // Functions
+ VCCustomBuildTool();
+ virtual ~VCCustomBuildTool(){}
+ bool parseOption(const char*){ return false; };
+
+ // Variables
+ QStringList AdditionalDependencies;
+ QStringList CommandLine;
+ QString Description;
+ QStringList Outputs;
+ QString ToolName;
+ QString ToolPath;
+};
+
+class VCResourceCompilerTool : public VCToolBase
+{
+public:
+ // Functions
+ VCResourceCompilerTool();
+ virtual ~VCResourceCompilerTool(){}
+ bool parseOption(const char*){ return false; };
+
+ // Variables
+ QStringList AdditionalIncludeDirectories;
+ QStringList AdditionalOptions;
+ enumResourceLangID Culture;
+ QStringList FullIncludePath;
+ triState IgnoreStandardIncludePath;
+ QStringList PreprocessorDefinitions;
+ QString ResourceOutputFileName;
+ linkProgressOption ShowProgress;
+ QString ToolPath;
+};
+
+class VCDeploymentTool
+{
+public:
+ // Functions
+ VCDeploymentTool();
+ virtual ~VCDeploymentTool() {}
+
+ // Variables
+ QString DeploymentTag;
+ QString RemoteDirectory;
+ RegisterDeployOption RegisterOutput;
+ QString AdditionalFiles;
+};
+
+class VCEventTool : public VCToolBase
+{
+protected:
+ // Functions
+ VCEventTool() : ExcludedFromBuild(unset){};
+ virtual ~VCEventTool(){}
+ bool parseOption(const char*){ return false; };
+
+public:
+ // Variables
+ QString CommandLine;
+ QString Description;
+ triState ExcludedFromBuild;
+ QString ToolName;
+ QString ToolPath;
+};
+
+class VCPostBuildEventTool : public VCEventTool
+{
+public:
+ VCPostBuildEventTool();
+ ~VCPostBuildEventTool(){}
+};
+
+class VCPreBuildEventTool : public VCEventTool
+{
+public:
+ VCPreBuildEventTool();
+ ~VCPreBuildEventTool(){}
+};
+
+class VCPreLinkEventTool : public VCEventTool
+{
+public:
+ VCPreLinkEventTool();
+ ~VCPreLinkEventTool(){}
+};
+
+class VCConfiguration
+{
+public:
+ // Functions
+ VCConfiguration();
+ ~VCConfiguration(){}
+
+ DotNET CompilerVersion;
+
+ // Variables
+ triState ATLMinimizesCRunTimeLibraryUsage;
+ triState BuildBrowserInformation;
+ charSet CharacterSet;
+ ConfigurationTypes ConfigurationType;
+ QString DeleteExtensionsOnClean;
+ QString ImportLibrary;
+ QString IntermediateDirectory;
+ QString Name;
+ QString OutputDirectory;
+ QString PrimaryOutput;
+ QString ProgramDatabase;
+ triState RegisterOutput;
+ useOfATL UseOfATL;
+ useOfMfc UseOfMfc;
+ triState WholeProgramOptimization;
+
+ // XML sub-parts
+ VCCLCompilerTool compiler;
+ VCLinkerTool linker;
+ VCLibrarianTool librarian;
+ VCCustomBuildTool custom;
+ VCMIDLTool idl;
+ VCPostBuildEventTool postBuild;
+ VCPreBuildEventTool preBuild;
+ VCDeploymentTool deployment;
+ VCPreLinkEventTool preLink;
+ VCResourceCompilerTool resource;
+};
+
+struct VCFilterFile
+{
+ VCFilterFile()
+ { excludeFromBuild = false; }
+ VCFilterFile(const QString &filename, bool exclude = false )
+ { file = filename; excludeFromBuild = exclude; }
+ VCFilterFile(const QString &filename, const QString &additional, bool exclude = false )
+ { file = filename; excludeFromBuild = exclude; additionalFile = additional; }
+ bool operator==(const VCFilterFile &other){
+ return file == other.file
+ && additionalFile == other.additionalFile
+ && excludeFromBuild == other.excludeFromBuild;
+ }
+
+ bool excludeFromBuild;
+ QString file;
+ QString additionalFile; // For tools like MOC
+};
+
+#ifndef QT_NO_DEBUG_OUTPUT
+inline QDebug operator<<(QDebug dbg, const VCFilterFile &p)
+{
+ dbg.nospace() << "VCFilterFile(file(" << p.file
+ << ") additionalFile(" << p.additionalFile
+ << ") excludeFromBuild(" << p.excludeFromBuild << "))" << endl;
+ return dbg.space();
+}
+#endif
+
+class VcprojGenerator;
+class VCFilter
+{
+public:
+ // Functions
+ VCFilter();
+ ~VCFilter(){};
+
+ void addFile(const QString& filename);
+ void addFile(const VCFilterFile& fileInfo);
+ void addFiles(const QStringList& fileList);
+ bool addExtraCompiler(const VCFilterFile &info);
+ void modifyPCHstage(QString str);
+ void outputFileConfig(XmlOutput &xml, const QString &filename);
+
+ // Variables
+ QString Name;
+ QString Filter;
+ QString Guid;
+ triState ParseFiles;
+ VcprojGenerator* Project;
+ VCConfiguration* Config;
+ QList<VCFilterFile> Files;
+
+ customBuildCheck CustomBuild;
+
+ bool useCustomBuildTool;
+ VCCustomBuildTool CustomBuildTool;
+
+ bool useCompilerTool;
+ VCCLCompilerTool CompilerTool;
+
+private:
+ friend XmlOutput &operator<<(XmlOutput &xml, VCFilter &tool);
+};
+
+typedef QList<VCFilter> VCFilterList;
+class VCProjectSingleConfig
+{
+public:
+ enum FilterTypes {
+ None,
+ Source,
+ Header,
+ Generated,
+ LexYacc,
+ Translation,
+ Resources,
+ Extras
+ };
+ // Functions
+ VCProjectSingleConfig(){};
+ ~VCProjectSingleConfig(){}
+
+ // Variables
+ QString Name;
+ QString Version;
+ QString ProjectGUID;
+ QString Keyword;
+ QString SccProjectName;
+ QString SccLocalPath;
+ QString PlatformName;
+
+ // XML sub-parts
+ VCConfiguration Configuration;
+ VCFilter RootFiles;
+ VCFilter SourceFiles;
+ VCFilter HeaderFiles;
+ VCFilter GeneratedFiles;
+ VCFilter LexYaccFiles;
+ VCFilter TranslationFiles;
+ VCFilter FormFiles;
+ VCFilter ResourceFiles;
+ VCFilterList ExtraCompilersFiles;
+
+ bool flat_files;
+
+ // Accessor for extracompilers
+ VCFilter &filterForExtraCompiler(const QString &compilerName);
+};
+
+
+
+// Tree & Flat view of files --------------------------------------------------
+class VCFilter;
+class Node
+{
+public:
+ virtual ~Node() { }
+ void addElement(const VCFilterFile &file) {
+ addElement(file.file, file);
+ }
+ virtual void addElement(const QString &filepath, const VCFilterFile &allInfo) = 0;
+ virtual void removeElements()= 0;
+ virtual void generateXML(XmlOutput &xml, const QString &tagName, VCProject &tool, const QString &filter) = 0;
+ virtual bool hasElements() = 0;
+};
+
+class TreeNode : public Node
+{
+ typedef QMap<QString, TreeNode*> ChildrenMap;
+ VCFilterFile info;
+ ChildrenMap children;
+
+public:
+ virtual ~TreeNode() { removeElements(); }
+
+ int pathIndex(const QString &filepath) {
+ int Windex = filepath.indexOf("\\");
+ int Uindex = filepath.indexOf("/");
+ if (Windex != -1 && Uindex != -1)
+ return qMin(Windex, Uindex);
+ else if (Windex != -1)
+ return Windex;
+ return Uindex;
+ }
+
+ void addElement(const QString &filepath, const VCFilterFile &allInfo){
+ QString newNodeName(filepath);
+
+ int index = pathIndex(filepath);
+ if (index != -1)
+ newNodeName = filepath.left(index);
+
+ TreeNode *n = children.value(newNodeName);
+ if (!n) {
+ n = new TreeNode;
+ n->info = allInfo;
+ children.insert(newNodeName, n);
+ }
+ if (index != -1)
+ n->addElement(filepath.mid(index+1), allInfo);
+ }
+
+ void removeElements() {
+ ChildrenMap::ConstIterator it = children.constBegin();
+ ChildrenMap::ConstIterator end = children.constEnd();
+ for( ; it != end; it++) {
+ (*it)->removeElements();
+ delete it.value();
+ }
+ children.clear();
+ }
+
+ void generateXML(XmlOutput &xml, const QString &tagName, VCProject &tool, const QString &filter);
+ bool hasElements() {
+ return children.size() != 0;
+ }
+};
+
+class FlatNode : public Node
+{
+ typedef QMap<QString, VCFilterFile> ChildrenMapFlat;
+ ChildrenMapFlat children;
+
+public:
+ virtual ~FlatNode() { removeElements(); }
+
+ int pathIndex(const QString &filepath) {
+ int Windex = filepath.lastIndexOf("\\");
+ int Uindex = filepath.lastIndexOf("/");
+ if (Windex != -1 && Uindex != -1)
+ return qMax(Windex, Uindex);
+ else if (Windex != -1)
+ return Windex;
+ return Uindex;
+ }
+
+ void addElement(const QString &filepath, const VCFilterFile &allInfo){
+ QString newKey(filepath);
+
+ int index = pathIndex(filepath);
+ if (index != -1)
+ newKey = filepath.mid(index+1);
+
+ // Key designed to sort files with same
+ // name in different paths correctly
+ children.insert(newKey + "\0" + allInfo.file, allInfo);
+ }
+
+ void removeElements() {
+ children.clear();
+ }
+
+ void generateXML(XmlOutput &xml, const QString &tagName, VCProject &proj, const QString &filter);
+ bool hasElements() {
+ return children.size() != 0;
+ }
+};
+// ----------------------------------------------------------------------------
+
+class VCProject
+{
+public:
+ // Variables
+ QString Name;
+ QString Version;
+ QString ProjectGUID;
+ QString Keyword;
+ QString SccProjectName;
+ QString SccLocalPath;
+ QString PlatformName;
+
+ // Single projects
+ QList<VCProjectSingleConfig> SingleProjects;
+
+ // List of all extracompilers
+ QStringList ExtraCompilers;
+
+ // Functions
+ void outputFilter(XmlOutput &xml,
+// VCProjectSingleConfig::FilterTypes type,
+ const QString &filtername);
+
+ void outputFileConfigs(XmlOutput &xml,
+// VCProjectSingleConfig::FilterTypes type,
+ const VCFilterFile &info,
+ const QString &filtername);
+};
+
+XmlOutput &operator<<(XmlOutput &, const VCCLCompilerTool &);
+XmlOutput &operator<<(XmlOutput &, const VCLinkerTool &);
+XmlOutput &operator<<(XmlOutput &, const VCMIDLTool &);
+XmlOutput &operator<<(XmlOutput &, const VCCustomBuildTool &);
+XmlOutput &operator<<(XmlOutput &, const VCLibrarianTool &);
+XmlOutput &operator<<(XmlOutput &, const VCResourceCompilerTool &);
+XmlOutput &operator<<(XmlOutput &, const VCEventTool &);
+XmlOutput &operator<<(XmlOutput &, const VCDeploymentTool &);
+XmlOutput &operator<<(XmlOutput &, const VCConfiguration &);
+XmlOutput &operator<<(XmlOutput &, VCFilter &);
+XmlOutput &operator<<(XmlOutput &, const VCProjectSingleConfig &);
+XmlOutput &operator<<(XmlOutput &, VCProject &);
+
+QT_END_NAMESPACE
+
+#endif // MSVC_OBJECTMODEL_H
diff --git a/qmake/generators/win32/msvc_vcproj.cpp b/qmake/generators/win32/msvc_vcproj.cpp
new file mode 100644
index 0000000..08159b0
--- /dev/null
+++ b/qmake/generators/win32/msvc_vcproj.cpp
@@ -0,0 +1,1785 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "msvc_vcproj.h"
+#include "option.h"
+#include "xmloutput.h"
+#include <qdir.h>
+#include <qdiriterator.h>
+#include <qcryptographichash.h>
+#include <qregexp.h>
+#include <qhash.h>
+#include <quuid.h>
+#include <stdlib.h>
+
+//#define DEBUG_SOLUTION_GEN
+//#define DEBUG_PROJECT_GEN
+
+QT_BEGIN_NAMESPACE
+// Filter GUIDs (Do NOT change these!) ------------------------------
+const char _GUIDSourceFiles[] = "{4FC737F1-C7A5-4376-A066-2A32D752A2FF}";
+const char _GUIDHeaderFiles[] = "{93995380-89BD-4b04-88EB-625FBE52EBFB}";
+const char _GUIDGeneratedFiles[] = "{71ED8ED8-ACB9-4CE9-BBE1-E00B30144E11}";
+const char _GUIDResourceFiles[] = "{D9D6E242-F8AF-46E4-B9FD-80ECBC20BA3E}";
+const char _GUIDLexYaccFiles[] = "{E12AE0D2-192F-4d59-BD23-7D3FA58D3183}";
+const char _GUIDTranslationFiles[] = "{639EADAA-A684-42e4-A9AD-28FC9BCB8F7C}";
+const char _GUIDFormFiles[] = "{99349809-55BA-4b9d-BF79-8FDBB0286EB3}";
+const char _GUIDExtraCompilerFiles[] = "{E0D8C965-CC5F-43d7-AD63-FAEF0BBC0F85}";
+QT_END_NAMESPACE
+
+#ifdef Q_OS_WIN32
+#include <qt_windows.h>
+
+QT_BEGIN_NAMESPACE
+
+struct {
+ DotNET version;
+ const char *versionStr;
+ const char *regKey;
+} dotNetCombo[] = {
+#ifdef Q_OS_WIN64
+ {NET2008, "MSVC.NET 2008 (9.0)", "Software\\Wow6432Node\\Microsoft\\VisualStudio\\9.0\\Setup\\VC\\ProductDir"},
+ {NET2008, "MSVC.NET 2008 Express Edition (9.0)", "Software\\Wow6432Node\\Microsoft\\VCExpress\\9.0\\Setup\\VC\\ProductDir"},
+ {NET2005, "MSVC.NET 2005 (8.0)", "Software\\Wow6432Node\\Microsoft\\VisualStudio\\8.0\\Setup\\VC\\ProductDir"},
+ {NET2005, "MSVC.NET 2005 Express Edition (8.0)", "Software\\Wow6432Node\\Microsoft\\VCExpress\\8.0\\Setup\\VC\\ProductDir"},
+ {NET2003, "MSVC.NET 2003 (7.1)", "Software\\Wow6432Node\\Microsoft\\VisualStudio\\7.1\\Setup\\VC\\ProductDir"},
+ {NET2002, "MSVC.NET 2002 (7.0)", "Software\\Wow6432Node\\Microsoft\\VisualStudio\\7.0\\Setup\\VC\\ProductDir"},
+#else
+ {NET2008, "MSVC.NET 2008 (9.0)", "Software\\Microsoft\\VisualStudio\\9.0\\Setup\\VC\\ProductDir"},
+ {NET2008, "MSVC.NET 2008 Express Edition (9.0)", "Software\\Microsoft\\VCExpress\\9.0\\Setup\\VC\\ProductDir"},
+ {NET2005, "MSVC.NET 2005 (8.0)", "Software\\Microsoft\\VisualStudio\\8.0\\Setup\\VC\\ProductDir"},
+ {NET2005, "MSVC.NET 2005 Express Edition (8.0)", "Software\\Microsoft\\VCExpress\\8.0\\Setup\\VC\\ProductDir"},
+ {NET2003, "MSVC.NET 2003 (7.1)", "Software\\Microsoft\\VisualStudio\\7.1\\Setup\\VC\\ProductDir"},
+ {NET2002, "MSVC.NET 2002 (7.0)", "Software\\Microsoft\\VisualStudio\\7.0\\Setup\\VC\\ProductDir"},
+#endif
+ {NETUnknown, "", ""},
+};
+
+static QString keyPath(const QString &rKey)
+{
+ int idx = rKey.lastIndexOf(QLatin1Char('\\'));
+ if (idx == -1)
+ return QString();
+ return rKey.left(idx + 1);
+}
+
+static QString keyName(const QString &rKey)
+{
+ int idx = rKey.lastIndexOf(QLatin1Char('\\'));
+ if (idx == -1)
+ return rKey;
+
+ QString res(rKey.mid(idx + 1));
+ if (res == "Default" || res == ".")
+ res = "";
+ return res;
+}
+
+static QString readRegistryKey(HKEY parentHandle, const QString &rSubkey)
+{
+
+ QString rSubkeyName = keyName(rSubkey);
+ QString rSubkeyPath = keyPath(rSubkey);
+
+ HKEY handle = 0;
+ LONG res;
+ QT_WA( {
+ res = RegOpenKeyExW(parentHandle, (WCHAR*)rSubkeyPath.utf16(),
+ 0, KEY_READ, &handle);
+ } , {
+ res = RegOpenKeyExA(parentHandle, rSubkeyPath.toLocal8Bit(),
+ 0, KEY_READ, &handle);
+ } );
+
+ if (res != ERROR_SUCCESS)
+ return QString();
+
+ // get the size and type of the value
+ DWORD dataType;
+ DWORD dataSize;
+ QT_WA( {
+ res = RegQueryValueExW(handle, (WCHAR*)rSubkeyName.utf16(), 0, &dataType, 0, &dataSize);
+ }, {
+ res = RegQueryValueExA(handle, rSubkeyName.toLocal8Bit(), 0, &dataType, 0, &dataSize);
+ } );
+ if (res != ERROR_SUCCESS) {
+ RegCloseKey(handle);
+ return QString();
+ }
+
+ // get the value
+ QByteArray data(dataSize, 0);
+ QT_WA( {
+ res = RegQueryValueExW(handle, (WCHAR*)rSubkeyName.utf16(), 0, 0,
+ reinterpret_cast<unsigned char*>(data.data()), &dataSize);
+ }, {
+ res = RegQueryValueExA(handle, rSubkeyName.toLocal8Bit(), 0, 0,
+ reinterpret_cast<unsigned char*>(data.data()), &dataSize);
+ } );
+ if (res != ERROR_SUCCESS) {
+ RegCloseKey(handle);
+ return QString();
+ }
+
+ QString result;
+ switch (dataType) {
+ case REG_EXPAND_SZ:
+ case REG_SZ: {
+ QT_WA( {
+ result = QString::fromUtf16(((const ushort*)data.constData()));
+ }, {
+ result = QString::fromLatin1(data.constData());
+ } );
+ break;
+ }
+
+ case REG_MULTI_SZ: {
+ QStringList l;
+ int i = 0;
+ for (;;) {
+ QString s;
+ QT_WA( {
+ s = QString::fromUtf16((const ushort*)data.constData() + i);
+ }, {
+ s = QString::fromLatin1(data.constData() + i);
+ } );
+ i += s.length() + 1;
+
+ if (s.isEmpty())
+ break;
+ l.append(s);
+ }
+ result = l.join(", ");
+ break;
+ }
+
+ case REG_NONE:
+ case REG_BINARY: {
+ QT_WA( {
+ result = QString::fromUtf16((const ushort*)data.constData(), data.size()/2);
+ }, {
+ result = QString::fromLatin1(data.constData(), data.size());
+ } );
+ break;
+ }
+
+ case REG_DWORD_BIG_ENDIAN:
+ case REG_DWORD: {
+ Q_ASSERT(data.size() == sizeof(int));
+ int i;
+ memcpy((char*)&i, data.constData(), sizeof(int));
+ result = QString::number(i);
+ break;
+ }
+
+ default:
+ qWarning("QSettings: unknown data %d type in windows registry", dataType);
+ break;
+ }
+
+ RegCloseKey(handle);
+ return result;
+}
+QT_END_NAMESPACE
+#endif
+
+QT_BEGIN_NAMESPACE
+DotNET which_dotnet_version()
+{
+#ifndef Q_OS_WIN32
+ return NET2002; // Always generate 7.0 versions on other platforms
+#else
+ // Only search for the version once
+ static DotNET current_version = NETUnknown;
+ if(current_version != NETUnknown)
+ return current_version;
+
+ // Fallback to .NET 2002
+ current_version = NET2002;
+
+ QStringList warnPath;
+ int installed = 0;
+ int i = 0;
+ for(; dotNetCombo[i].version; ++i) {
+ QString path = readRegistryKey(HKEY_LOCAL_MACHINE, dotNetCombo[i].regKey);
+ if(!path.isEmpty()) {
+ ++installed;
+ current_version = dotNetCombo[i].version;
+ warnPath += QString("%1").arg(dotNetCombo[i].versionStr);
+ }
+ }
+
+ if (installed < 2)
+ return current_version;
+
+ // More than one version installed, search directory path
+ QString paths = qgetenv("PATH");
+ QStringList pathlist = paths.toLower().split(";");
+
+ i = installed = 0;
+ for(; dotNetCombo[i].version; ++i) {
+ QString productPath = readRegistryKey(HKEY_LOCAL_MACHINE, dotNetCombo[i].regKey).toLower();
+ if (productPath.isEmpty())
+ continue;
+ QStringList::iterator it;
+ for(it = pathlist.begin(); it != pathlist.end(); ++it) {
+ if((*it).contains(productPath)) {
+ ++installed;
+ current_version = dotNetCombo[i].version;
+ warnPath += QString("%1 in path").arg(dotNetCombo[i].versionStr);
+ break;
+ }
+ }
+ }
+ switch(installed) {
+ case 1:
+ break;
+ case 0:
+ warn_msg(WarnLogic, "Generator: MSVC.NET: Found more than one version of Visual Studio, but"
+ " none in your path! Fallback to lowest version (%s)", warnPath.join(", ").toLatin1().data());
+ break;
+ default:
+ warn_msg(WarnLogic, "Generator: MSVC.NET: Found more than one version of Visual Studio in"
+ " your path! Fallback to lowest version (%s)", warnPath.join(", ").toLatin1().data());
+ break;
+ }
+
+ return current_version;
+#endif
+};
+
+// Flatfile Tags ----------------------------------------------------
+const char _slnHeader70[] = "Microsoft Visual Studio Solution File, Format Version 7.00";
+const char _slnHeader71[] = "Microsoft Visual Studio Solution File, Format Version 8.00";
+const char _slnHeader80[] = "Microsoft Visual Studio Solution File, Format Version 9.00";
+const char _slnHeader90[] = "Microsoft Visual Studio Solution File, Format Version 10.00";
+ // The following UUID _may_ change for later servicepacks...
+ // If so we need to search through the registry at
+ // HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\7.0\Projects
+ // to find the subkey that contains a "PossibleProjectExtension"
+ // containing "vcproj"...
+ // Use the hardcoded value for now so projects generated on other
+ // platforms are actually usable.
+const char _slnMSVCvcprojGUID[] = "{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}";
+const char _slnProjectBeg[] = "\nProject(\"";
+const char _slnProjectMid[] = "\") = ";
+const char _slnProjectEnd[] = "\nEndProject";
+const char _slnGlobalBeg[] = "\nGlobal";
+const char _slnGlobalEnd[] = "\nEndGlobal";
+const char _slnSolutionConf[] = "\n\tGlobalSection(SolutionConfiguration) = preSolution"
+ "\n\t\tConfigName.0 = Debug|Win32"
+ "\n\t\tConfigName.1 = Release|Win32"
+ "\n\tEndGlobalSection";
+const char _slnProjDepBeg[] = "\n\tGlobalSection(ProjectDependencies) = postSolution";
+const char _slnProjDepEnd[] = "\n\tEndGlobalSection";
+const char _slnProjConfBeg[] = "\n\tGlobalSection(ProjectConfiguration) = postSolution";
+const char _slnProjRelConfTag1[]= ".Release|%1.ActiveCfg = Release|";
+const char _slnProjRelConfTag2[]= ".Release|%1.Build.0 = Release|";
+const char _slnProjDbgConfTag1[]= ".Debug|%1.ActiveCfg = Debug|";
+const char _slnProjDbgConfTag2[]= ".Debug|%1.Build.0 = Debug|";
+const char _slnProjConfEnd[] = "\n\tEndGlobalSection";
+const char _slnExtSections[] = "\n\tGlobalSection(ExtensibilityGlobals) = postSolution"
+ "\n\tEndGlobalSection"
+ "\n\tGlobalSection(ExtensibilityAddIns) = postSolution"
+ "\n\tEndGlobalSection";
+// ------------------------------------------------------------------
+
+VcprojGenerator::VcprojGenerator() : Win32MakefileGenerator(), init_flag(false)
+{
+}
+bool VcprojGenerator::writeMakefile(QTextStream &t)
+{
+ initProject(); // Fills the whole project with proper data
+
+ // Generate solution file
+ if(project->first("TEMPLATE") == "vcsubdirs") {
+ if (!project->isActiveConfig("build_pass")) {
+ debug_msg(1, "Generator: MSVC.NET: Writing solution file");
+ writeSubDirs(t);
+ } else {
+ debug_msg(1, "Generator: MSVC.NET: Not writing solution file for build_pass configs");
+ }
+ return true;
+ } else
+ // Generate single configuration project file
+ if (project->first("TEMPLATE") == "vcapp" ||
+ project->first("TEMPLATE") == "vclib") {
+ if(!project->isActiveConfig("build_pass")) {
+ debug_msg(1, "Generator: MSVC.NET: Writing single configuration project file");
+ XmlOutput xmlOut(t);
+ xmlOut << vcProject;
+ }
+ return true;
+ }
+ return project->isActiveConfig("build_pass");
+}
+
+bool VcprojGenerator::writeProjectMakefile()
+{
+ usePlatformDir();
+ QTextStream t(&Option::output);
+
+ // Check if all requirements are fulfilled
+ if(!project->values("QMAKE_FAILED_REQUIREMENTS").isEmpty()) {
+ fprintf(stderr, "Project file not generated because all requirements not met:\n\t%s\n",
+ var("QMAKE_FAILED_REQUIREMENTS").toLatin1().constData());
+ return true;
+ }
+
+ // Generate project file
+ if(project->first("TEMPLATE") == "vcapp" ||
+ project->first("TEMPLATE") == "vclib") {
+ if (!mergedProjects.count()) {
+ warn_msg(WarnLogic, "Generator: MSVC.NET: no single configuration created, cannot output project!");
+ return false;
+ }
+
+ debug_msg(1, "Generator: MSVC.NET: Writing project file");
+ VCProject mergedProject;
+ for (int i = 0; i < mergedProjects.count(); ++i) {
+ VCProjectSingleConfig *singleProject = &(mergedProjects.at(i)->vcProject);
+ mergedProject.SingleProjects += *singleProject;
+ for (int j = 0; j < singleProject->ExtraCompilersFiles.count(); ++j) {
+ const QString &compilerName = singleProject->ExtraCompilersFiles.at(j).Name;
+ if (!mergedProject.ExtraCompilers.contains(compilerName))
+ mergedProject.ExtraCompilers += compilerName;
+ }
+ }
+
+ if(mergedProjects.count() > 1 &&
+ mergedProjects.at(0)->vcProject.Name ==
+ mergedProjects.at(1)->vcProject.Name)
+ mergedProjects.at(0)->writePrlFile();
+ mergedProject.Name = unescapeFilePath(project->first("QMAKE_ORIG_TARGET"));
+ mergedProject.Version = mergedProjects.at(0)->vcProject.Version;
+ mergedProject.ProjectGUID = project->isEmpty("QMAKE_UUID") ? getProjectUUID().toString().toUpper() : project->first("QMAKE_UUID");
+ mergedProject.Keyword = project->first("VCPROJ_KEYWORD");
+ mergedProject.SccProjectName = mergedProjects.at(0)->vcProject.SccProjectName;
+ mergedProject.SccLocalPath = mergedProjects.at(0)->vcProject.SccLocalPath;
+ mergedProject.PlatformName = mergedProjects.at(0)->vcProject.PlatformName;
+
+ XmlOutput xmlOut(t);
+ xmlOut << mergedProject;
+ return true;
+ } else if(project->first("TEMPLATE") == "vcsubdirs") {
+ return writeMakefile(t);
+ }
+ return false;
+}
+
+struct VcsolutionDepend {
+ QString uuid;
+ QString vcprojFile, orig_target, target;
+ Target targetType;
+ QStringList dependencies;
+};
+
+QUuid VcprojGenerator::getProjectUUID(const QString &filename)
+{
+ bool validUUID = true;
+
+ // Read GUID from variable-space
+ QUuid uuid = project->first("GUID");
+
+ // If none, create one based on the MD5 of absolute project path
+ if(uuid.isNull() || !filename.isEmpty()) {
+ QString abspath = Option::fixPathToLocalOS(filename.isEmpty()?project->first("QMAKE_MAKEFILE"):filename);
+ QByteArray digest = QCryptographicHash::hash(abspath.toUtf8(), QCryptographicHash::Md5);
+ memcpy((unsigned char*)(&uuid), digest.constData(), sizeof(QUuid));
+ validUUID = !uuid.isNull();
+ uuid.data4[0] = (uuid.data4[0] & 0x3F) | 0x80; // UV_DCE variant
+ uuid.data3 = (uuid.data3 & 0x0FFF) | (QUuid::Name<<12);
+ }
+
+ // If still not valid, generate new one, and suggest adding to .pro
+ if(uuid.isNull() || !validUUID) {
+ uuid = QUuid::createUuid();
+ fprintf(stderr,
+ "qmake couldn't create a GUID based on filepath, and we couldn't\nfind a valid GUID in the .pro file (Consider adding\n'GUID = %s' to the .pro file)\n",
+ uuid.toString().toUpper().toLatin1().constData());
+ }
+
+ // Store GUID in variable-space
+ project->values("GUID") = QStringList(uuid.toString().toUpper());
+ return uuid;
+}
+
+QUuid VcprojGenerator::increaseUUID(const QUuid &id)
+{
+ QUuid result(id);
+ qint64 dataFirst = (result.data4[0] << 24) +
+ (result.data4[1] << 16) +
+ (result.data4[2] << 8) +
+ result.data4[3];
+ qint64 dataLast = (result.data4[4] << 24) +
+ (result.data4[5] << 16) +
+ (result.data4[6] << 8) +
+ result.data4[7];
+
+ if(!(dataLast++))
+ dataFirst++;
+
+ result.data4[0] = uchar((dataFirst >> 24) & 0xff);
+ result.data4[1] = uchar((dataFirst >> 16) & 0xff);
+ result.data4[2] = uchar((dataFirst >> 8) & 0xff);
+ result.data4[3] = uchar(dataFirst & 0xff);
+ result.data4[4] = uchar((dataLast >> 24) & 0xff);
+ result.data4[5] = uchar((dataLast >> 16) & 0xff);
+ result.data4[6] = uchar((dataLast >> 8) & 0xff);
+ result.data4[7] = uchar(dataLast & 0xff);
+ return result;
+}
+
+void VcprojGenerator::writeSubDirs(QTextStream &t)
+{
+ // Check if all requirements are fulfilled
+ if(!project->values("QMAKE_FAILED_REQUIREMENTS").isEmpty()) {
+ fprintf(stderr, "Project file not generated because all requirements not met:\n\t%s\n",
+ var("QMAKE_FAILED_REQUIREMENTS").toLatin1().constData());
+ return;
+ }
+
+ switch(which_dotnet_version()) {
+ case NET2008:
+ t << _slnHeader90;
+ break;
+ case NET2005:
+ t << _slnHeader80;
+ break;
+ case NET2003:
+ t << _slnHeader71;
+ break;
+ case NET2002:
+ t << _slnHeader70;
+ break;
+ default:
+ t << _slnHeader70;
+ warn_msg(WarnLogic, "Generator: MSVC.NET: Unknown version (%d) of MSVC detected for .sln", which_dotnet_version());
+ break;
+ }
+
+ QHash<QString, VcsolutionDepend*> solution_depends;
+ QList<VcsolutionDepend*> solution_cleanup;
+
+ QStringList subdirs = project->values("SUBDIRS");
+ QString oldpwd = qmake_getpwd();
+
+ // Make sure that all temp projects are configured
+ // for release so that the depends are created
+ // without the debug <lib>dxxx.lib name mangling
+ QStringList old_after_vars = Option::after_user_vars;
+ Option::after_user_vars.append("CONFIG+=release");
+
+ for(int i = 0; i < subdirs.size(); ++i) {
+ QString tmp = subdirs.at(i);
+ if(!project->isEmpty(tmp + ".file")) {
+ if(!project->isEmpty(tmp + ".subdir"))
+ warn_msg(WarnLogic, "Cannot assign both file and subdir for subdir %s",
+ tmp.toLatin1().constData());
+ tmp = project->first(tmp + ".file");
+ } else if(!project->isEmpty(tmp + ".subdir")) {
+ tmp = project->first(tmp + ".subdir");
+ }
+ QFileInfo fi(fileInfo(Option::fixPathToLocalOS(tmp, true)));
+ if(fi.exists()) {
+ if(fi.isDir()) {
+ QString profile = tmp;
+ if(!profile.endsWith(Option::dir_sep))
+ profile += Option::dir_sep;
+ profile += fi.baseName() + ".pro";
+ subdirs.append(profile);
+ } else {
+ QMakeProject tmp_proj;
+ QString dir = fi.path(), fn = fi.fileName();
+ if(!dir.isEmpty()) {
+ if(!qmake_setpwd(dir))
+ fprintf(stderr, "Cannot find directory: %s\n", dir.toLatin1().constData());
+ }
+ if(tmp_proj.read(fn)) {
+ // Check if all requirements are fulfilled
+ if(!tmp_proj.variables()["QMAKE_FAILED_REQUIREMENTS"].isEmpty()) {
+ fprintf(stderr, "Project file(%s) not added to Solution because all requirements not met:\n\t%s\n",
+ fn.toLatin1().constData(), tmp_proj.values("QMAKE_FAILED_REQUIREMENTS").join(" ").toLatin1().constData());
+ continue;
+ }
+ if(tmp_proj.first("TEMPLATE") == "vcsubdirs") {
+ QStringList tmp_proj_subdirs = tmp_proj.variables()["SUBDIRS"];
+ for(int x = 0; x < tmp_proj_subdirs.size(); ++x) {
+ QString tmpdir = tmp_proj_subdirs.at(x);
+ if(!tmp_proj.isEmpty(tmpdir + ".file")) {
+ if(!tmp_proj.isEmpty(tmpdir + ".subdir"))
+ warn_msg(WarnLogic, "Cannot assign both file and subdir for subdir %s",
+ tmpdir.toLatin1().constData());
+ tmpdir = tmp_proj.first(tmpdir + ".file");
+ } else if(!tmp_proj.isEmpty(tmpdir + ".subdir")) {
+ tmpdir = tmp_proj.first(tmpdir + ".subdir");
+ }
+ subdirs += fileFixify(tmpdir);
+ }
+ } else if(tmp_proj.first("TEMPLATE") == "vcapp" || tmp_proj.first("TEMPLATE") == "vclib") {
+ // Initialize a 'fake' project to get the correct variables
+ // and to be able to extract all the dependencies
+ Option::QMAKE_MODE old_mode = Option::qmake_mode;
+ Option::qmake_mode = Option::QMAKE_GENERATE_NOTHING;
+ VcprojGenerator tmp_vcproj;
+ tmp_vcproj.setNoIO(true);
+ tmp_vcproj.setProjectFile(&tmp_proj);
+ Option::qmake_mode = old_mode;
+ if(Option::debug_level) {
+ QMap<QString, QStringList> &vars = tmp_proj.variables();
+ for(QMap<QString, QStringList>::Iterator it = vars.begin();
+ it != vars.end(); ++it) {
+ if(it.key().left(1) != "." && !it.value().isEmpty())
+ debug_msg(1, "%s: %s === %s", fn.toLatin1().constData(), it.key().toLatin1().constData(),
+ it.value().join(" :: ").toLatin1().constData());
+ }
+ }
+
+ // We assume project filename is [QMAKE_ORIG_TARGET].vcproj
+ QString vcproj = unescapeFilePath(fixFilename(tmp_vcproj.project->first("QMAKE_ORIG_TARGET")) + project->first("VCPROJ_EXTENSION"));
+ QString vcprojDir = qmake_getpwd();
+
+ // If file doesn't exsist, then maybe the users configuration
+ // doesn't allow it to be created. Skip to next...
+ if(!exists(vcprojDir + Option::dir_sep + vcproj)) {
+
+ // Try to find the directory which fits relative
+ // to the output path, which represents the shadow
+ // path in case we are shadow building
+ QStringList list = fi.path().split(QLatin1Char('/'));
+ QString tmpDir = QFileInfo(Option::output).path() + Option::dir_sep;
+ bool found = false;
+ for (int i = list.size() - 1; i >= 0; --i) {
+ QString curr;
+ for (int j = i; j < list.size(); ++j)
+ curr += list.at(j) + Option::dir_sep;
+ if (exists(tmpDir + curr + vcproj)) {
+ vcprojDir = QDir::cleanPath(tmpDir + curr);
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ warn_msg(WarnLogic, "Ignored (not found) '%s'", QString(vcprojDir + Option::dir_sep + vcproj).toLatin1().constData());
+ goto nextfile; // # Dirty!
+ }
+ }
+
+ VcsolutionDepend *newDep = new VcsolutionDepend;
+ newDep->vcprojFile = vcprojDir + Option::dir_sep + vcproj;
+ newDep->orig_target = unescapeFilePath(tmp_proj.first("QMAKE_ORIG_TARGET"));
+ newDep->target = tmp_proj.first("MSVCPROJ_TARGET").section(Option::dir_sep, -1);
+ newDep->targetType = tmp_vcproj.projectTarget;
+ newDep->uuid = tmp_proj.isEmpty("QMAKE_UUID") ? getProjectUUID(Option::fixPathToLocalOS(vcprojDir + QDir::separator() + vcproj)).toString().toUpper(): tmp_proj.first("QMAKE_UUID");
+
+ // We want to store it as the .lib name.
+ if(newDep->target.endsWith(".dll"))
+ newDep->target = newDep->target.left(newDep->target.length()-3) + "lib";
+
+ // All ActiveQt Server projects are dependent on idc.exe
+ if(tmp_proj.variables()["CONFIG"].contains("qaxserver"))
+ newDep->dependencies << "idc.exe";
+
+ // All extra compilers which has valid input are considered dependencies
+ const QStringList &quc = tmp_proj.variables()["QMAKE_EXTRA_COMPILERS"];
+ for(QStringList::ConstIterator it = quc.constBegin(); it != quc.constEnd(); ++it) {
+ const QStringList &invar = tmp_proj.variables().value((*it) + ".input");
+ for(QStringList::ConstIterator iit = invar.constBegin(); iit != invar.constEnd(); ++iit) {
+ const QStringList fileList = tmp_proj.variables().value(*iit);
+ if (!fileList.isEmpty()) {
+ const QStringList &cmdsParts = tmp_proj.variables().value((*it) + ".commands");
+ bool startOfLine = true;
+ foreach(QString cmd, cmdsParts) {
+ if (!startOfLine) {
+ if (cmd.contains("\r"))
+ startOfLine = true;
+ continue;
+ }
+ if (cmd.isEmpty())
+ continue;
+
+ startOfLine = false;
+ // Extra compiler commands might be defined in variables, so
+ // expand them (don't care about the in/out files)
+ cmd = tmp_vcproj.replaceExtraCompilerVariables(cmd, QStringList(), QStringList());
+ // Pull out command based on spaces and quoting, if the
+ // command starts with that
+ cmd = cmd.left(cmd.indexOf(cmd.at(0) == '"' ? '"' : ' ', 1));
+ QString dep = cmd.section('/', -1).section('\\', -1);
+ if (!newDep->dependencies.contains(dep))
+ newDep->dependencies << dep;
+ }
+ }
+ }
+ }
+
+ // Add all unknown libs to the deps
+ QStringList where("QMAKE_LIBS");
+ if(!tmp_proj.isEmpty("QMAKE_INTERNAL_PRL_LIBS"))
+ where = tmp_proj.variables()["QMAKE_INTERNAL_PRL_LIBS"];
+ for(QStringList::iterator wit = where.begin();
+ wit != where.end(); ++wit) {
+ QStringList &l = tmp_proj.variables()[(*wit)];
+ for(QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
+ QString opt = (*it);
+ if(!opt.startsWith("/") && // Not a switch
+ opt != newDep->target && // Not self
+ opt != "opengl32.lib" && // We don't care about these libs
+ opt != "glu32.lib" && // to make depgen alittle faster
+ opt != "kernel32.lib" &&
+ opt != "user32.lib" &&
+ opt != "gdi32.lib" &&
+ opt != "comdlg32.lib" &&
+ opt != "advapi32.lib" &&
+ opt != "shell32.lib" &&
+ opt != "ole32.lib" &&
+ opt != "oleaut32.lib" &&
+ opt != "uuid.lib" &&
+ opt != "imm32.lib" &&
+ opt != "winmm.lib" &&
+ opt != "wsock32.lib" &&
+ opt != "ws2_32.lib" &&
+ opt != "winspool.lib" &&
+ opt != "delayimp.lib")
+ {
+ newDep->dependencies << opt.section(Option::dir_sep, -1);
+ }
+ }
+ }
+#ifdef DEBUG_SOLUTION_GEN
+ qDebug("Deps for %20s: [%s]", newDep->target.toLatin1().constData(), newDep->dependencies.join(" :: ").toLatin1().constData());
+#endif
+ solution_cleanup.append(newDep);
+ solution_depends.insert(newDep->target, newDep);
+ t << _slnProjectBeg << _slnMSVCvcprojGUID << _slnProjectMid
+ << "\"" << newDep->orig_target << "\", \"" << newDep->vcprojFile
+ << "\", \"" << newDep->uuid << "\"";
+ t << _slnProjectEnd;
+ }
+ }
+nextfile:
+ qmake_setpwd(oldpwd);
+ }
+ }
+ }
+ t << _slnGlobalBeg;
+ if (!project->isEmpty("CE_SDK") && !project->isEmpty("CE_ARCH")) {
+ QString slnConfCE = _slnSolutionConf;
+ QString platform = QString("|") + project->values("CE_SDK").join(" ") + " (" + project->first("CE_ARCH") + ")";
+ slnConfCE.replace(QString("|Win32"), platform);
+ t << slnConfCE;
+ } else {
+ t << _slnSolutionConf;
+ }
+ t << _slnProjDepBeg;
+
+ // Restore previous after_user_var options
+ Option::after_user_vars = old_after_vars;
+
+ // Figure out dependencies
+ for(QList<VcsolutionDepend*>::Iterator it = solution_cleanup.begin(); it != solution_cleanup.end(); ++it) {
+ int cnt = 0;
+ for(QStringList::iterator dit = (*it)->dependencies.begin(); dit != (*it)->dependencies.end(); ++dit) {
+ if(VcsolutionDepend *vc = solution_depends[*dit])
+ t << "\n\t\t" << (*it)->uuid << "." << cnt++ << " = " << vc->uuid;
+ }
+ }
+ t << _slnProjDepEnd;
+ t << _slnProjConfBeg;
+ for(QList<VcsolutionDepend*>::Iterator it = solution_cleanup.begin(); it != solution_cleanup.end(); ++it) {
+ QString platform = "Win32";
+ if (!project->isEmpty("CE_SDK") && !project->isEmpty("CE_ARCH"))
+ platform = project->values("CE_SDK").join(" ") + " (" + project->first("CE_ARCH") + ")";
+ t << "\n\t\t" << (*it)->uuid << QString(_slnProjDbgConfTag1).arg(platform) << platform;
+ t << "\n\t\t" << (*it)->uuid << QString(_slnProjDbgConfTag2).arg(platform) << platform;
+ t << "\n\t\t" << (*it)->uuid << QString(_slnProjRelConfTag1).arg(platform) << platform;
+ t << "\n\t\t" << (*it)->uuid << QString(_slnProjRelConfTag2).arg(platform) << platform;
+ }
+ t << _slnProjConfEnd;
+ t << _slnExtSections;
+ t << _slnGlobalEnd;
+
+
+ while (!solution_cleanup.isEmpty())
+ delete solution_cleanup.takeFirst();
+}
+
+// ------------------------------------------------------------------------------------------------
+// ------------------------------------------------------------------------------------------------
+
+bool VcprojGenerator::hasBuiltinCompiler(const QString &file)
+{
+ // Source files
+ for (int i = 0; i < Option::cpp_ext.count(); ++i)
+ if (file.endsWith(Option::cpp_ext.at(i)))
+ return true;
+ for (int i = 0; i < Option::c_ext.count(); ++i)
+ if (file.endsWith(Option::c_ext.at(i)))
+ return true;
+ if (file.endsWith(".rc")
+ || file.endsWith(".idl"))
+ return true;
+ return false;
+}
+
+void VcprojGenerator::init()
+{
+ if(init_flag)
+ return;
+ if(project->first("TEMPLATE") == "vcsubdirs") { //too much work for subdirs
+ init_flag = true;
+ return;
+ }
+
+ debug_msg(1, "Generator: MSVC.NET: Initializing variables");
+
+ // this should probably not be here, but I'm using it to wrap the .t files
+ if (project->first("TEMPLATE") == "vcapp")
+ project->values("QMAKE_APP_FLAG").append("1");
+ else if (project->first("TEMPLATE") == "vclib")
+ project->values("QMAKE_LIB_FLAG").append("1");
+ if (project->values("QMAKESPEC").isEmpty())
+ project->values("QMAKESPEC").append(qgetenv("QMAKESPEC"));
+
+ processVars();
+ initOld(); // Currently calling old DSP code to set variables. CLEAN UP!
+
+ // Figure out what we're trying to build
+ if(project->first("TEMPLATE") == "vcapp") {
+ projectTarget = Application;
+ } else if(project->first("TEMPLATE") == "vclib") {
+ if(project->isActiveConfig("staticlib")) {
+ if (!project->values("RES_FILE").isEmpty())
+ project->values("MSVCPROJ_LIBS") += escapeFilePaths(project->values("RES_FILE"));
+ projectTarget = StaticLib;
+ } else
+ projectTarget = SharedLib;
+ }
+
+ // Setup PCH variables
+ precompH = project->first("PRECOMPILED_HEADER");
+ precompCPP = project->first("PRECOMPILED_SOURCE");
+ usePCH = !precompH.isEmpty() && project->isActiveConfig("precompile_header");
+ if (usePCH) {
+ precompHFilename = fileInfo(precompH).fileName();
+ // Created files
+ QString origTarget = unescapeFilePath(project->first("QMAKE_ORIG_TARGET"));
+ precompObj = origTarget + Option::obj_ext;
+ precompPch = origTarget + ".pch";
+ // Add PRECOMPILED_HEADER to HEADERS
+ if (!project->values("HEADERS").contains(precompH))
+ project->values("HEADERS") += precompH;
+ // Return to variable pool
+ project->values("PRECOMPILED_OBJECT") = QStringList(precompObj);
+ project->values("PRECOMPILED_PCH") = QStringList(precompPch);
+
+ autogenPrecompCPP = precompCPP.isEmpty() && project->isActiveConfig("autogen_precompile_source");
+ if (autogenPrecompCPP) {
+ precompCPP = precompH
+ + (Option::cpp_ext.count() ? Option::cpp_ext.at(0) : QLatin1String(".cpp"));
+ project->values("GENERATED_SOURCES") += precompCPP;
+ } else if (!precompCPP.isEmpty()) {
+ project->values("SOURCES") += precompCPP;
+ }
+ }
+
+ // Add all input files for a custom compiler into a map for uniqueness,
+ // unless the compiler is configure as a combined stage, then use the first one
+ const QStringList &quc = project->values("QMAKE_EXTRA_COMPILERS");
+ for(QStringList::ConstIterator it = quc.constBegin(); it != quc.constEnd(); ++it) {
+ const QStringList &invar = project->variables().value((*it) + ".input");
+ const QString compiler_out = project->first((*it) + ".output");
+ for(QStringList::ConstIterator iit = invar.constBegin(); iit != invar.constEnd(); ++iit) {
+ QStringList fileList = project->variables().value(*iit);
+ if (!fileList.isEmpty()) {
+ if (project->values((*it) + ".CONFIG").indexOf("combine") != -1)
+ fileList = QStringList(fileList.first());
+ for(QStringList::ConstIterator fit = fileList.constBegin(); fit != fileList.constEnd(); ++fit) {
+ QString file = (*fit);
+ if (verifyExtraCompiler((*it), file)) {
+ if (!hasBuiltinCompiler(file)) {
+ extraCompilerSources[file] += *it;
+ } else {
+ QString out = Option::fixPathToTargetOS(replaceExtraCompilerVariables(
+ compiler_out, file, QString()), false);
+ extraCompilerSources[out] += *it;
+ extraCompilerOutputs[out] = QStringList(file); // Can only have one
+ }
+ }
+ }
+ }
+ }
+ }
+
+#if 0 // Debugging
+ Q_FOREACH(QString aKey, extraCompilerSources.keys()) {
+ qDebug("Extracompilers for %s are (%s)", aKey.toLatin1().constData(), extraCompilerSources.value(aKey).join(", ").toLatin1().constData());
+ }
+ Q_FOREACH(QString aKey, extraCompilerOutputs.keys()) {
+ qDebug("Object mapping for %s is (%s)", aKey.toLatin1().constData(), extraCompilerOutputs.value(aKey).join(", ").toLatin1().constData());
+ }
+ qDebug("");
+#endif
+}
+
+bool VcprojGenerator::mergeBuildProject(MakefileGenerator *other)
+{
+ VcprojGenerator *otherVC = static_cast<VcprojGenerator*>(other);
+ if (!otherVC) {
+ warn_msg(WarnLogic, "VcprojGenerator: Cannot merge other types of projects! (ignored)");
+ return false;
+ }
+ mergedProjects += otherVC;
+ return true;
+}
+
+void VcprojGenerator::initProject()
+{
+ // Initialize XML sub elements
+ // - Do this first since project elements may need
+ // - to know of certain configuration options
+ initConfiguration();
+ initRootFiles();
+ initSourceFiles();
+ initHeaderFiles();
+ initGeneratedFiles();
+ initLexYaccFiles();
+ initTranslationFiles();
+ initFormFiles();
+ initResourceFiles();
+ initExtraCompilerOutputs();
+
+ // Own elements -----------------------------
+ vcProject.Name = unescapeFilePath(project->first("QMAKE_ORIG_TARGET"));
+ switch(which_dotnet_version()) {
+ case NET2008:
+ vcProject.Version = "9,00";
+ break;
+ case NET2005:
+ //### using ',' because of a bug in 2005 B2
+ //### VS uses '.' or ',' depending on the regional settings! Using ',' always works.
+ vcProject.Version = "8,00";
+ break;
+ case NET2003:
+ vcProject.Version = "7.10";
+ break;
+ case NET2002:
+ vcProject.Version = "7.00";
+ break;
+ default:
+ vcProject.Version = "7.00";
+ warn_msg(WarnLogic, "Generator: MSVC.NET: Unknown version (%d) of MSVC detected for .vcproj", which_dotnet_version());
+ break;
+ }
+
+ vcProject.Keyword = project->first("VCPROJ_KEYWORD");
+ if (project->isEmpty("CE_SDK") || project->isEmpty("CE_ARCH")) {
+ vcProject.PlatformName = (vcProject.Configuration.idl.TargetEnvironment == midlTargetWin64 ? "Win64" : "Win32");
+ } else {
+ vcProject.PlatformName = project->values("CE_SDK").join(" ") + " (" + project->first("CE_ARCH") + ")";
+ }
+ // These are not used by Qt, but may be used by customers
+ vcProject.SccProjectName = project->first("SCCPROJECTNAME");
+ vcProject.SccLocalPath = project->first("SCCLOCALPATH");
+ vcProject.flat_files = project->isActiveConfig("flat");
+}
+
+void VcprojGenerator::initConfiguration()
+{
+ // Initialize XML sub elements
+ // - Do this first since main configuration elements may need
+ // - to know of certain compiler/linker options
+ VCConfiguration &conf = vcProject.Configuration;
+ conf.CompilerVersion = which_dotnet_version();
+
+ initCompilerTool();
+
+ // Only on configuration per build
+ bool isDebug = project->isActiveConfig("debug");
+
+ if(projectTarget == StaticLib)
+ initLibrarianTool();
+ else {
+ conf.linker.GenerateDebugInformation = isDebug ? _True : _False;
+ initLinkerTool();
+ }
+ initResourceTool();
+ initIDLTool();
+
+ // Own elements -----------------------------
+ QString temp = project->first("BuildBrowserInformation");
+ switch (projectTarget) {
+ case SharedLib:
+ conf.ConfigurationType = typeDynamicLibrary;
+ break;
+ case StaticLib:
+ conf.ConfigurationType = typeStaticLibrary;
+ break;
+ case Application:
+ default:
+ conf.ConfigurationType = typeApplication;
+ break;
+ }
+
+ conf.Name = project->values("BUILD_NAME").join(" ");
+ if (conf.Name.isEmpty())
+ conf.Name = isDebug ? "Debug" : "Release";
+ if (project->isEmpty("CE_SDK") || project->isEmpty("CE_ARCH")) {
+ conf.Name += (conf.idl.TargetEnvironment == midlTargetWin64 ? "|Win64" : "|Win32");
+ } else {
+ conf.Name += "|" + project->values("CE_SDK").join(" ") + " (" + project->first("CE_ARCH") + ")";
+ }
+ conf.ATLMinimizesCRunTimeLibraryUsage = (project->first("ATLMinimizesCRunTimeLibraryUsage").isEmpty() ? _False : _True);
+ conf.BuildBrowserInformation = triState(temp.isEmpty() ? (short)unset : temp.toShort());
+ temp = project->first("CharacterSet");
+ conf.CharacterSet = charSet(temp.isEmpty() ? (short)charSetNotSet : temp.toShort());
+ conf.DeleteExtensionsOnClean = project->first("DeleteExtensionsOnClean");
+ conf.ImportLibrary = conf.linker.ImportLibrary;
+ conf.IntermediateDirectory = project->first("OBJECTS_DIR");
+ conf.OutputDirectory = ".";
+ conf.PrimaryOutput = project->first("PrimaryOutput");
+ conf.WholeProgramOptimization = conf.compiler.WholeProgramOptimization;
+ temp = project->first("UseOfATL");
+ if(!temp.isEmpty())
+ conf.UseOfATL = useOfATL(temp.toShort());
+ temp = project->first("UseOfMfc");
+ if(!temp.isEmpty())
+ conf.UseOfMfc = useOfMfc(temp.toShort());
+
+ // Configuration does not need parameters from
+ // these sub XML items;
+ initCustomBuildTool();
+ initPreBuildEventTools();
+ initPostBuildEventTools();
+ // Only deploy for CE projects
+ if (!project->isEmpty("CE_SDK") && !project->isEmpty("CE_ARCH"))
+ initDeploymentTool();
+ initPreLinkEventTools();
+
+ // Set definite values in both configurations
+ if (isDebug) {
+ conf.compiler.PreprocessorDefinitions.removeAll("NDEBUG");
+ } else {
+ conf.compiler.PreprocessorDefinitions += "NDEBUG";
+ }
+
+}
+
+void VcprojGenerator::initCompilerTool()
+{
+ QString placement = project->first("OBJECTS_DIR");
+ if(placement.isEmpty())
+ placement = ".\\";
+
+ VCConfiguration &conf = vcProject.Configuration;
+ conf.compiler.AssemblerListingLocation = placement ;
+ conf.compiler.ProgramDataBaseFileName = ".\\" ;
+ conf.compiler.ObjectFile = placement ;
+ // PCH
+ if (usePCH) {
+ conf.compiler.UsePrecompiledHeader = pchUseUsingSpecific;
+ conf.compiler.PrecompiledHeaderFile = "$(IntDir)\\" + precompPch;
+ conf.compiler.PrecompiledHeaderThrough = project->first("PRECOMPILED_HEADER");
+ conf.compiler.ForcedIncludeFiles = project->values("PRECOMPILED_HEADER");
+ // Minimal build option triggers an Internal Compiler Error
+ // when used in conjunction with /FI and /Yu, so remove it
+ project->values("QMAKE_CFLAGS_DEBUG").removeAll("-Gm");
+ project->values("QMAKE_CFLAGS_DEBUG").removeAll("/Gm");
+ project->values("QMAKE_CXXFLAGS_DEBUG").removeAll("-Gm");
+ project->values("QMAKE_CXXFLAGS_DEBUG").removeAll("/Gm");
+ }
+
+ conf.compiler.parseOptions(project->values("QMAKE_CXXFLAGS"));
+ if(project->isActiveConfig("debug")){
+ // Debug version
+ conf.compiler.parseOptions(project->values("QMAKE_CXXFLAGS"));
+ conf.compiler.parseOptions(project->values("QMAKE_CXXFLAGS_DEBUG"));
+ if((projectTarget == Application) || (projectTarget == StaticLib))
+ conf.compiler.parseOptions(project->values("QMAKE_CXXFLAGS_MT_DBG"));
+ else
+ conf.compiler.parseOptions(project->values("QMAKE_CXXFLAGS_MT_DLLDBG"));
+ } else {
+ // Release version
+ conf.compiler.parseOptions(project->values("QMAKE_CXXFLAGS"));
+ conf.compiler.parseOptions(project->values("QMAKE_CXXFLAGS_RELEASE"));
+ conf.compiler.PreprocessorDefinitions += "QT_NO_DEBUG";
+ conf.compiler.PreprocessorDefinitions += "NDEBUG";
+ if((projectTarget == Application) || (projectTarget == StaticLib))
+ conf.compiler.parseOptions(project->values("QMAKE_CXXFLAGS_MT"));
+ else
+ conf.compiler.parseOptions(project->values("QMAKE_CXXFLAGS_MT_DLL"));
+ }
+
+ // Common for both release and debug
+ if(project->isActiveConfig("warn_off"))
+ conf.compiler.parseOptions(project->values("QMAKE_CXXFLAGS_WARN_OFF"));
+ else if(project->isActiveConfig("warn_on"))
+ conf.compiler.parseOptions(project->values("QMAKE_CXXFLAGS_WARN_ON"));
+ if(project->isActiveConfig("windows"))
+ conf.compiler.PreprocessorDefinitions += project->values("MSVCPROJ_WINCONDEF");
+
+ // Can this be set for ALL configs?
+ // If so, use qmake.conf!
+ if(projectTarget == SharedLib)
+ conf.compiler.PreprocessorDefinitions += "_WINDOWS";
+
+ conf.compiler.PreprocessorDefinitions += project->values("DEFINES");
+ conf.compiler.PreprocessorDefinitions += project->values("PRL_EXPORT_DEFINES");
+ conf.compiler.parseOptions(project->values("MSVCPROJ_INCPATH"));
+}
+
+void VcprojGenerator::initLibrarianTool()
+{
+ VCConfiguration &conf = vcProject.Configuration;
+ conf.librarian.OutputFile = project->first("DESTDIR");
+ if(conf.librarian.OutputFile.isEmpty())
+ conf.librarian.OutputFile = ".\\";
+
+ if(!conf.librarian.OutputFile.endsWith("\\"))
+ conf.librarian.OutputFile += '\\';
+
+ conf.librarian.OutputFile += project->first("MSVCPROJ_TARGET");
+ conf.librarian.AdditionalOptions += project->values("QMAKE_LIBFLAGS");
+}
+
+void VcprojGenerator::initLinkerTool()
+{
+ findLibraries(); // Need to add the highest version of the libs
+ VCConfiguration &conf = vcProject.Configuration;
+ conf.linker.parseOptions(project->values("MSVCPROJ_LFLAGS"));
+
+ foreach(QString libs, project->values("MSVCPROJ_LIBS")) {
+ if (libs.left(9).toUpper() == "/LIBPATH:") {
+ QStringList l = QStringList(libs);
+ conf.linker.parseOptions(l);
+ } else {
+ conf.linker.AdditionalDependencies += libs;
+ }
+ }
+
+ switch (projectTarget) {
+ case Application:
+ conf.linker.OutputFile = project->first("DESTDIR");
+ break;
+ case SharedLib:
+ conf.linker.parseOptions(project->values("MSVCPROJ_LIBOPTIONS"));
+ conf.linker.OutputFile = project->first("DESTDIR");
+ break;
+ case StaticLib: //unhandled - added to remove warnings..
+ break;
+ }
+
+ if(conf.linker.OutputFile.isEmpty())
+ conf.linker.OutputFile = ".\\";
+
+ if(!conf.linker.OutputFile.endsWith("\\"))
+ conf.linker.OutputFile += '\\';
+
+ conf.linker.OutputFile += project->first("MSVCPROJ_TARGET");
+
+ if(project->isActiveConfig("debug")){
+ conf.linker.parseOptions(project->values("QMAKE_LFLAGS_DEBUG"));
+ } else {
+ conf.linker.parseOptions(project->values("QMAKE_LFLAGS_RELEASE"));
+ }
+
+ if(project->isActiveConfig("dll")){
+ conf.linker.parseOptions(project->values("QMAKE_LFLAGS_QT_DLL"));
+ }
+
+ if(project->isActiveConfig("console")){
+ conf.linker.parseOptions(project->values("QMAKE_LFLAGS_CONSOLE"));
+ } else {
+ conf.linker.parseOptions(project->values("QMAKE_LFLAGS_WINDOWS"));
+ }
+
+}
+
+void VcprojGenerator::initResourceTool()
+{
+ VCConfiguration &conf = vcProject.Configuration;
+ conf.resource.PreprocessorDefinitions = conf.compiler.PreprocessorDefinitions;
+
+ // We need to add _DEBUG for the debug version of the project, since the normal compiler defines
+ // do not contain it. (The compiler defines this symbol automatically, which is wy we don't need
+ // to add it for the compiler) However, the resource tool does not do this.
+ if(project->isActiveConfig("debug"))
+ conf.resource.PreprocessorDefinitions += "_DEBUG";
+ if(project->isActiveConfig("staticlib"))
+ conf.resource.ResourceOutputFileName = project->first("DESTDIR") + "/$(InputName).res";
+}
+
+
+void VcprojGenerator::initIDLTool()
+{
+}
+
+void VcprojGenerator::initCustomBuildTool()
+{
+}
+
+void VcprojGenerator::initPreBuildEventTools()
+{
+}
+
+QString VcprojGenerator::fixCommandLine(DotNET version, const QString &input) const
+{
+ QString result = input;
+
+ if (version >= NET2005)
+ result = result.replace(QLatin1Char('\n'), QLatin1String("&#x000D;&#x000A;"));
+
+ return result;
+}
+
+void VcprojGenerator::initPostBuildEventTools()
+{
+ VCConfiguration &conf = vcProject.Configuration;
+ if(!project->values("QMAKE_POST_LINK").isEmpty()) {
+ QString cmdline = fixCommandLine(conf.CompilerVersion, var("QMAKE_POST_LINK"));
+ conf.postBuild.CommandLine = cmdline;
+ if (conf.CompilerVersion < NET2005)
+ cmdline = cmdline.replace("\n", "&&");
+ conf.postBuild.Description = cmdline;
+ }
+
+ QString signature = !project->isEmpty("SIGNATURE_FILE") ? var("SIGNATURE_FILE") : var("DEFAULT_SIGNATURE");
+ bool useSignature = !signature.isEmpty() && !project->isActiveConfig("staticlib") &&
+ !project->isEmpty("CE_SDK") && !project->isEmpty("CE_ARCH");
+ if(useSignature)
+ conf.postBuild.CommandLine.prepend(QLatin1String("signtool sign /F ") + signature + " \"$(TargetPath)\"\n" +
+ (!conf.postBuild.CommandLine.isEmpty() ? " && " : ""));
+
+ if(!project->values("MSVCPROJ_COPY_DLL").isEmpty()) {
+ if(!conf.postBuild.CommandLine.isEmpty())
+ conf.postBuild.CommandLine += " && ";
+ conf.postBuild.Description += var("MSVCPROJ_COPY_DLL_DESC");
+ conf.postBuild.CommandLine += var("MSVCPROJ_COPY_DLL");
+ }
+}
+
+void VcprojGenerator::initDeploymentTool()
+{
+ VCConfiguration &conf = vcProject.Configuration;
+ QString targetPath = project->values("deploy.path").join(" ");
+ if (targetPath.isEmpty())
+ targetPath = QString("%CSIDL_PROGRAM_FILES%\\") + project->first("TARGET");
+ if (targetPath.endsWith("/") || targetPath.endsWith("\\"))
+ targetPath = targetPath.mid(0,targetPath.size()-1);
+
+ // Only deploy Qt libs for shared build
+ if (!project->values("QMAKE_QT_DLL").isEmpty()) {
+ QStringList& arg = project->values("MSVCPROJ_LIBS");
+ for (QStringList::ConstIterator it = arg.constBegin(); it != arg.constEnd(); ++it) {
+ if (it->contains(project->first("QMAKE_LIBDIR"))) {
+ QString dllName = *it;
+
+ if (dllName.contains(QLatin1String("QAxContainer"))
+ || dllName.contains(QLatin1String("qtmain"))
+ || dllName.contains(QLatin1String("QtUiTools")))
+ continue;
+ dllName.replace(QLatin1String(".lib") , QLatin1String(".dll"));
+ QFileInfo info(dllName);
+ conf.deployment.AdditionalFiles += info.fileName()
+ + "|" + QDir::toNativeSeparators(info.absolutePath())
+ + "|" + targetPath
+ + "|0;";
+ }
+ }
+ }
+
+ // C-runtime deployment
+ QString runtime = project->values("QT_CE_C_RUNTIME").join(QLatin1String(" "));
+ if (!runtime.isEmpty() && (runtime != QLatin1String("no"))) {
+ QString runtimeVersion = QLatin1String("msvcr");
+ QString mkspec = project->first("QMAKESPEC");
+ // If no .qmake.cache has been found, we fallback to the original mkspec
+ if (mkspec.isEmpty())
+ mkspec = project->first("QMAKESPEC_ORIGINAL");
+
+ if (!mkspec.isEmpty()) {
+ if (mkspec.endsWith("2008"))
+ runtimeVersion.append("90");
+ else
+ runtimeVersion.append("80");
+ if (project->isActiveConfig("debug"))
+ runtimeVersion.append("d");
+ runtimeVersion.append(".dll");
+
+ if (runtime == "yes") {
+ // Auto-find C-runtime
+ QString vcInstallDir = qgetenv("VCINSTALLDIR");
+ if (!vcInstallDir.isEmpty()) {
+ vcInstallDir += "\\ce\\dll\\";
+ vcInstallDir += project->values("CE_ARCH").join(QLatin1String(" "));
+ if (!QFileInfo(vcInstallDir + QDir::separator() + runtimeVersion).exists())
+ runtime.clear();
+ else
+ runtime = vcInstallDir;
+ }
+ }
+ }
+
+ if (!runtime.isEmpty() && runtime != QLatin1String("yes")) {
+ conf.deployment.AdditionalFiles += runtimeVersion
+ + "|" + QDir::toNativeSeparators(runtime)
+ + "|" + targetPath
+ + "|0;";
+ }
+ }
+
+ // foreach item in DEPLOYMENT
+ foreach(QString item, project->values("DEPLOYMENT")) {
+ // get item.path
+ QString devicePath = project->first(item + ".path");
+ // if the path does not exist, skip it
+ if (devicePath.isEmpty())
+ continue;
+ // check if item.path is relative (! either /,\ or %)
+ if (!(devicePath.at(0) == QLatin1Char('/')
+ || devicePath.at(0) == QLatin1Char('\\')
+ || devicePath.at(0) == QLatin1Char('%'))) {
+ // create output path
+ devicePath = Option::fixPathToLocalOS(QDir::cleanPath(targetPath + QLatin1Char('\\') + devicePath));
+ }
+ // foreach d in item.sources
+ foreach(QString source, project->values(item + ".sources")) {
+ QString itemDevicePath = devicePath;
+ source = Option::fixPathToLocalOS(source);
+ QString nameFilter;
+ QFileInfo info(source);
+ QString searchPath;
+ if (info.isDir()) {
+ nameFilter = QLatin1String("*");
+ itemDevicePath += "\\" + info.fileName();
+ searchPath = info.absoluteFilePath();
+ } else {
+ nameFilter = source.split('\\').last();
+ searchPath = info.absolutePath();
+ }
+
+ int pathSize = searchPath.size();
+ QDirIterator iterator(searchPath, QStringList() << nameFilter
+ , QDir::Files | QDir::NoDotAndDotDot | QDir::NoSymLinks
+ , QDirIterator::Subdirectories);
+ // foreach dirIterator-entry in d
+ while(iterator.hasNext()) {
+ iterator.next();
+ QString absoluteItemPath = Option::fixPathToLocalOS(QFileInfo(iterator.filePath()).absolutePath());
+ // Identify if it is just another subdir
+ int diffSize = absoluteItemPath.size() - pathSize;
+ // write out rules
+ conf.deployment.AdditionalFiles += iterator.fileName()
+ + "|" + absoluteItemPath
+ + "|" + itemDevicePath + (diffSize ? (absoluteItemPath.right(diffSize)) : QLatin1String(""))
+ + "|0;";
+ }
+ }
+ }
+}
+
+void VcprojGenerator::initPreLinkEventTools()
+{
+ VCConfiguration &conf = vcProject.Configuration;
+ if(!project->values("QMAKE_PRE_LINK").isEmpty()) {
+ QString cmdline = fixCommandLine(conf.CompilerVersion, var("QMAKE_PRE_LINK"));
+ conf.preLink.Description = cmdline;
+ conf.preLink.CommandLine = cmdline;
+ }
+}
+
+void VcprojGenerator::initRootFiles()
+{
+ // Note: Root files do _not_ have any filter name, filter nor GUID!
+ vcProject.RootFiles.addFiles(project->values("RC_FILE"));
+
+ vcProject.RootFiles.Project = this;
+ vcProject.RootFiles.Config = &(vcProject.Configuration);
+ vcProject.RootFiles.CustomBuild = none;
+}
+
+void VcprojGenerator::initSourceFiles()
+{
+ vcProject.SourceFiles.Name = "Source Files";
+ vcProject.SourceFiles.Filter = "cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx";
+ vcProject.SourceFiles.Guid = _GUIDSourceFiles;
+
+ vcProject.SourceFiles.addFiles(project->values("SOURCES"));
+
+ vcProject.SourceFiles.Project = this;
+ vcProject.SourceFiles.Config = &(vcProject.Configuration);
+ vcProject.SourceFiles.CustomBuild = none;
+}
+
+void VcprojGenerator::initHeaderFiles()
+{
+ vcProject.HeaderFiles.Name = "Header Files";
+ vcProject.HeaderFiles.Filter = "h;hpp;hxx;hm;inl;inc;xsd";
+ vcProject.HeaderFiles.Guid = _GUIDHeaderFiles;
+
+ vcProject.HeaderFiles.addFiles(project->values("HEADERS"));
+ if (usePCH) // Generated PCH cpp file
+ vcProject.HeaderFiles.addFile(precompH);
+
+ vcProject.HeaderFiles.Project = this;
+ vcProject.HeaderFiles.Config = &(vcProject.Configuration);
+// vcProject.HeaderFiles.CustomBuild = mocHdr;
+// addMocArguments(vcProject.HeaderFiles);
+}
+
+void VcprojGenerator::initGeneratedFiles()
+{
+ vcProject.GeneratedFiles.Name = "Generated Files";
+ vcProject.GeneratedFiles.Filter = "cpp;c;cxx;moc;h;def;odl;idl;res;";
+ vcProject.GeneratedFiles.Guid = _GUIDGeneratedFiles;
+
+ // ### These cannot have CustomBuild (mocSrc)!!
+ vcProject.GeneratedFiles.addFiles(project->values("GENERATED_SOURCES"));
+ vcProject.GeneratedFiles.addFiles(project->values("GENERATED_FILES"));
+ vcProject.GeneratedFiles.addFiles(project->values("IDLSOURCES"));
+ vcProject.GeneratedFiles.addFiles(project->values("RES_FILE"));
+ vcProject.GeneratedFiles.addFiles(project->values("QMAKE_IMAGE_COLLECTION")); // compat
+ if(!extraCompilerOutputs.isEmpty())
+ vcProject.GeneratedFiles.addFiles(extraCompilerOutputs.keys());
+
+ vcProject.GeneratedFiles.Project = this;
+ vcProject.GeneratedFiles.Config = &(vcProject.Configuration);
+// vcProject.GeneratedFiles.CustomBuild = mocSrc;
+}
+
+void VcprojGenerator::initLexYaccFiles()
+{
+ vcProject.LexYaccFiles.Name = "Lex / Yacc Files";
+ vcProject.LexYaccFiles.ParseFiles = _False;
+ vcProject.LexYaccFiles.Filter = "l;y";
+ vcProject.LexYaccFiles.Guid = _GUIDLexYaccFiles;
+
+ vcProject.LexYaccFiles.addFiles(project->values("LEXSOURCES"));
+ vcProject.LexYaccFiles.addFiles(project->values("YACCSOURCES"));
+
+ vcProject.LexYaccFiles.Project = this;
+ vcProject.LexYaccFiles.Config = &(vcProject.Configuration);
+ vcProject.LexYaccFiles.CustomBuild = lexyacc;
+}
+
+void VcprojGenerator::initTranslationFiles()
+{
+ vcProject.TranslationFiles.Name = "Translation Files";
+ vcProject.TranslationFiles.ParseFiles = _False;
+ vcProject.TranslationFiles.Filter = "ts;xlf";
+ vcProject.TranslationFiles.Guid = _GUIDTranslationFiles;
+
+ vcProject.TranslationFiles.addFiles(project->values("TRANSLATIONS"));
+
+ vcProject.TranslationFiles.Project = this;
+ vcProject.TranslationFiles.Config = &(vcProject.Configuration);
+ vcProject.TranslationFiles.CustomBuild = none;
+}
+
+
+void VcprojGenerator::initFormFiles()
+{
+ vcProject.FormFiles.Name = "Form Files";
+ vcProject.FormFiles.ParseFiles = _False;
+ vcProject.FormFiles.Filter = "ui";
+ vcProject.FormFiles.Guid = _GUIDFormFiles;
+
+ vcProject.FormFiles.addFiles(project->values("FORMS"));
+ vcProject.FormFiles.addFiles(project->values("FORMS3"));
+
+ vcProject.FormFiles.Project = this;
+ vcProject.FormFiles.Config = &(vcProject.Configuration);
+ vcProject.FormFiles.CustomBuild = none;
+}
+
+
+void VcprojGenerator::initResourceFiles()
+{
+ vcProject.ResourceFiles.Name = "Resource Files";
+ vcProject.ResourceFiles.ParseFiles = _False;
+ vcProject.ResourceFiles.Filter = "qrc;*"; //"rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;ts;xlf;qrc";
+ vcProject.ResourceFiles.Guid = _GUIDResourceFiles;
+
+ // Bad hack, please look away -------------------------------------
+ QString rcc_dep_cmd = project->values("rcc.depend_command").join(" ");
+ if(!rcc_dep_cmd.isEmpty()) {
+ QStringList qrc_files = project->values("RESOURCES");
+ QStringList deps;
+ if(!qrc_files.isEmpty()) {
+ for (int i = 0; i < qrc_files.count(); ++i) {
+ char buff[256];
+ QString dep_cmd = replaceExtraCompilerVariables(rcc_dep_cmd, qrc_files.at(i),"");
+
+ dep_cmd = Option::fixPathToLocalOS(dep_cmd, true, false);
+ if(canExecute(dep_cmd)) {
+ if(FILE *proc = QT_POPEN(dep_cmd.toLatin1().constData(), "r")) {
+ QString indeps;
+ while(!feof(proc)) {
+ int read_in = (int)fread(buff, 1, 255, proc);
+ if(!read_in)
+ break;
+ indeps += QByteArray(buff, read_in);
+ }
+ QT_PCLOSE(proc);
+ if(!indeps.isEmpty())
+ deps += fileFixify(indeps.replace('\n', ' ').simplified().split(' '));
+ }
+ }
+ }
+ vcProject.ResourceFiles.addFiles(deps);
+ }
+ }
+ // You may look again --------------------------------------------
+
+ vcProject.ResourceFiles.addFiles(project->values("RESOURCES"));
+ vcProject.ResourceFiles.addFiles(project->values("IMAGES"));
+
+ vcProject.ResourceFiles.Project = this;
+ vcProject.ResourceFiles.Config = &(vcProject.Configuration);
+ vcProject.ResourceFiles.CustomBuild = none;
+}
+
+void VcprojGenerator::initExtraCompilerOutputs()
+{
+ QStringList otherFilters;
+ otherFilters << "FORMS"
+ << "FORMS3"
+ << "GENERATED_FILES"
+ << "GENERATED_SOURCES"
+ << "HEADERS"
+ << "IDLSOURCES"
+ << "IMAGES"
+ << "LEXSOURCES"
+ << "QMAKE_IMAGE_COLLECTION"
+ << "RC_FILE"
+ << "RESOURCES"
+ << "RES_FILE"
+ << "SOURCES"
+ << "TRANSLATIONS"
+ << "YACCSOURCES";
+ const QStringList &quc = project->values("QMAKE_EXTRA_COMPILERS");
+ for(QStringList::ConstIterator it = quc.begin(); it != quc.end(); ++it) {
+ QString extracompilerName = project->first((*it) + ".name");
+ if (extracompilerName.isEmpty())
+ extracompilerName = (*it);
+
+ // Create an extra compiler filter and add the files
+ VCFilter extraCompile;
+ extraCompile.Name = extracompilerName;
+ extraCompile.ParseFiles = _False;
+ extraCompile.Filter = "";
+ extraCompile.Guid = QString(_GUIDExtraCompilerFiles) + "-" + (*it);
+
+
+ // If the extra compiler has a variable_out set the output file
+ // is added to an other file list, and does not need its own..
+ bool addOnInput = hasBuiltinCompiler(project->first((*it) + ".output"));
+ QString tmp_other_out = project->first((*it) + ".variable_out");
+ if (!tmp_other_out.isEmpty() && !addOnInput)
+ continue;
+
+ if (!addOnInput) {
+ QString tmp_out = project->first((*it) + ".output");
+ if (project->values((*it) + ".CONFIG").indexOf("combine") != -1) {
+ // Combined output, only one file result
+ extraCompile.addFile(
+ Option::fixPathToTargetOS(replaceExtraCompilerVariables(tmp_out, QString(), QString()), false));
+ } else {
+ // One output file per input
+ QStringList tmp_in = project->values(project->first((*it) + ".input"));
+ for (int i = 0; i < tmp_in.count(); ++i) {
+ const QString &filename = tmp_in.at(i);
+ if (extraCompilerSources.contains(filename))
+ extraCompile.addFile(
+ Option::fixPathToTargetOS(replaceExtraCompilerVariables(filename, tmp_out, QString()), false));
+ }
+ }
+ } else {
+ // In this case we the outputs have a built-in compiler, so we cannot add the custom
+ // build steps there. So, we turn it around and add it to the input files instead,
+ // provided that the input file variable is not handled already (those in otherFilters
+ // are handled, so we avoid them).
+ QStringList inputVars = project->values((*it) + ".input");
+ foreach(QString inputVar, inputVars) {
+ if (!otherFilters.contains(inputVar)) {
+ QStringList tmp_in = project->values(inputVar);
+ for (int i = 0; i < tmp_in.count(); ++i) {
+ const QString &filename = tmp_in.at(i);
+ if (extraCompilerSources.contains(filename))
+ extraCompile.addFile(
+ Option::fixPathToTargetOS(replaceExtraCompilerVariables(filename, QString(), QString()), false));
+ }
+ }
+ }
+ }
+ extraCompile.Project = this;
+ extraCompile.Config = &(vcProject.Configuration);
+ extraCompile.CustomBuild = none;
+
+ vcProject.ExtraCompilersFiles.append(extraCompile);
+ }
+}
+
+/* \internal
+ Sets up all needed variables from the environment and all the different caches and .conf files
+*/
+
+void VcprojGenerator::initOld()
+{
+ if(init_flag)
+ return;
+
+ init_flag = true;
+ QStringList::Iterator it;
+
+ // Decode version, and add it to $$MSVCPROJ_VERSION --------------
+ if(!project->values("VERSION").isEmpty()) {
+ QString version = project->values("VERSION")[0];
+ int firstDot = version.indexOf(".");
+ QString major = version.left(firstDot);
+ QString minor = version.right(version.length() - firstDot - 1);
+ minor.replace(QRegExp("\\."), "");
+ project->values("MSVCPROJ_VERSION").append("/VERSION:" + major + "." + minor);
+ project->values("QMAKE_LFLAGS").append("/VERSION:" + major + "." + minor);
+ }
+
+ project->values("QMAKE_LIBS") += escapeFilePaths(project->values("LIBS"));
+
+ // Get filename w/o extension -----------------------------------
+ QString msvcproj_project = "";
+ QString targetfilename = "";
+ if(!project->isEmpty("TARGET")) {
+ project->values("TARGET") = unescapeFilePaths(project->values("TARGET"));
+ targetfilename = msvcproj_project = project->first("TARGET");
+ }
+
+ // Init base class too -------------------------------------------
+ MakefileGenerator::init();
+
+ if(msvcproj_project.isEmpty())
+ msvcproj_project = Option::output.fileName();
+
+ msvcproj_project = msvcproj_project.right(msvcproj_project.length() - msvcproj_project.lastIndexOf("\\") - 1);
+ msvcproj_project = msvcproj_project.left(msvcproj_project.lastIndexOf("."));
+ msvcproj_project.replace(QRegExp("-"), "");
+
+ project->values("MSVCPROJ_PROJECT").append(msvcproj_project);
+ QStringList &proj = project->values("MSVCPROJ_PROJECT");
+
+ for(it = proj.begin(); it != proj.end(); ++it)
+ (*it).replace(QRegExp("\\.[a-zA-Z0-9_]*$"), "");
+
+ // SUBSYSTEM -----------------------------------------------------
+ if(!project->values("QMAKE_APP_FLAG").isEmpty()) {
+ project->values("MSVCPROJ_TEMPLATE").append("win32app" + project->first("VCPROJ_EXTENSION"));
+ if(project->isActiveConfig("console")) {
+ project->values("MSVCPROJ_CONSOLE").append("CONSOLE");
+ project->values("MSVCPROJ_WINCONDEF").append("_CONSOLE");
+ project->values("MSVCPROJ_VCPROJTYPE").append("0x0103");
+ project->values("MSVCPROJ_SUBSYSTEM").append("CONSOLE");
+ } else {
+ project->values("MSVCPROJ_CONSOLE").clear();
+ project->values("MSVCPROJ_WINCONDEF").append("_WINDOWS");
+ project->values("MSVCPROJ_VCPROJTYPE").append("0x0101");
+ project->values("MSVCPROJ_SUBSYSTEM").append("WINDOWS");
+ }
+ }
+
+ // $$QMAKE.. -> $$MSVCPROJ.. -------------------------------------
+ project->values("MSVCPROJ_LIBS") += project->values("QMAKE_LIBS");
+ project->values("MSVCPROJ_LFLAGS") += project->values("QMAKE_LFLAGS");
+ if(!project->values("QMAKE_LIBDIR").isEmpty()) {
+ QStringList strl = project->values("QMAKE_LIBDIR");
+ QStringList::iterator stri;
+ for(stri = strl.begin(); stri != strl.end(); ++stri) {
+ if(!(*stri).startsWith("/LIBPATH:"))
+ (*stri).prepend("/LIBPATH:");
+ }
+ project->values("MSVCPROJ_LFLAGS") += strl;
+ }
+ project->values("MSVCPROJ_CXXFLAGS") += project->values("QMAKE_CXXFLAGS");
+ QStringList &incs = project->values("INCLUDEPATH");
+ for(QStringList::Iterator incit = incs.begin(); incit != incs.end(); ++incit) {
+ QString inc = (*incit);
+ if (!inc.startsWith('"') && !inc.endsWith('"'))
+ inc = QString("\"%1\"").arg(inc); // Quote all paths if not quoted already
+ project->values("MSVCPROJ_INCPATH").append("-I" + inc);
+ }
+ project->values("MSVCPROJ_INCPATH").append("-I" + specdir());
+
+ QString dest;
+ project->values("MSVCPROJ_TARGET") = QStringList(project->first("TARGET"));
+ Option::fixPathToTargetOS(project->first("TARGET"));
+ dest = project->first("TARGET") + project->first("TARGET_EXT");
+ project->values("MSVCPROJ_TARGET") = QStringList(dest);
+
+ // DLL COPY ------------------------------------------------------
+ if(project->isActiveConfig("dll") && !project->values("DLLDESTDIR").isEmpty()) {
+ QStringList dlldirs = project->values("DLLDESTDIR");
+ QString copydll("");
+ QStringList::Iterator dlldir;
+ for(dlldir = dlldirs.begin(); dlldir != dlldirs.end(); ++dlldir) {
+ if(!copydll.isEmpty())
+ copydll += " && ";
+ copydll += "copy \"$(TargetPath)\" \"" + *dlldir + "\"";
+ }
+
+ QString deststr("Copy " + dest + " to ");
+ for(dlldir = dlldirs.begin(); dlldir != dlldirs.end();) {
+ deststr += *dlldir;
+ ++dlldir;
+ if(dlldir != dlldirs.end())
+ deststr += ", ";
+ }
+
+ project->values("MSVCPROJ_COPY_DLL").append(copydll);
+ project->values("MSVCPROJ_COPY_DLL_DESC").append(deststr);
+ }
+
+ if (!project->values("DEF_FILE").isEmpty())
+ project->values("MSVCPROJ_LFLAGS").append("/DEF:"+project->first("DEF_FILE"));
+
+ project->values("QMAKE_INTERNAL_PRL_LIBS") << "MSVCPROJ_LIBS";
+
+ // Verbose output if "-d -d"...
+ outputVariables();
+}
+
+// ------------------------------------------------------------------------------------------------
+// ------------------------------------------------------------------------------------------------
+
+QString VcprojGenerator::replaceExtraCompilerVariables(const QString &var, const QStringList &in, const QStringList &out)
+{
+ QString ret = MakefileGenerator::replaceExtraCompilerVariables(var, in, out);
+
+ QStringList &defines = project->values("VCPROJ_MAKEFILE_DEFINES");
+ if(defines.isEmpty())
+ defines.append(varGlue("PRL_EXPORT_DEFINES"," -D"," -D","") +
+ varGlue("DEFINES"," -D"," -D",""));
+ ret.replace("$(DEFINES)", defines.first());
+
+ QStringList &incpath = project->values("VCPROJ_MAKEFILE_INCPATH");
+ if(incpath.isEmpty() && !this->var("MSVCPROJ_INCPATH").isEmpty())
+ incpath.append(this->var("MSVCPROJ_INCPATH"));
+ ret.replace("$(INCPATH)", incpath.join(" "));
+
+ return ret;
+}
+
+
+
+bool VcprojGenerator::openOutput(QFile &file, const QString &/*build*/) const
+{
+ QString outdir;
+ if(!file.fileName().isEmpty()) {
+ QFileInfo fi(fileInfo(file.fileName()));
+ if(fi.isDir())
+ outdir = file.fileName() + QDir::separator();
+ }
+ if(!outdir.isEmpty() || file.fileName().isEmpty()) {
+ QString ext = project->first("VCPROJ_EXTENSION");
+ if(project->first("TEMPLATE") == "vcsubdirs")
+ ext = project->first("VCSOLUTION_EXTENSION");
+ QString outputName = unescapeFilePath(project->first("TARGET"));
+ if (!project->first("MAKEFILE").isEmpty())
+ outputName = project->first("MAKEFILE");
+ file.setFileName(outdir + outputName + ext);
+ }
+ return Win32MakefileGenerator::openOutput(file, QString());
+}
+
+QString VcprojGenerator::fixFilename(QString ofile) const
+{
+ ofile = Option::fixPathToLocalOS(ofile);
+ int slashfind = ofile.lastIndexOf(Option::dir_sep);
+ if(slashfind == -1) {
+ ofile = ofile.replace('-', '_');
+ } else {
+ int hypenfind = ofile.indexOf('-', slashfind);
+ while (hypenfind != -1 && slashfind < hypenfind) {
+ ofile = ofile.replace(hypenfind, 1, '_');
+ hypenfind = ofile.indexOf('-', hypenfind + 1);
+ }
+ }
+ return ofile;
+}
+
+QString VcprojGenerator::findTemplate(QString file)
+{
+ QString ret;
+ if(!exists((ret = file)) &&
+ !exists((ret = QString(Option::mkfile::qmakespec + "/" + file))) &&
+ !exists((ret = QString(QLibraryInfo::location(QLibraryInfo::DataPath) + "/win32-msvc.net/" + file))) &&
+ !exists((ret = QString(QLibraryInfo::location(QLibraryInfo::DataPath) + "/win32-msvc2002/" + file))) &&
+ !exists((ret = QString(QLibraryInfo::location(QLibraryInfo::DataPath) + "/win32-msvc2003/" + file))) &&
+ !exists((ret = QString(QLibraryInfo::location(QLibraryInfo::DataPath) + "/win32-msvc2005/" + file))) &&
+ !exists((ret = QString(QLibraryInfo::location(QLibraryInfo::DataPath) + "/win32-msvc2008/" + file))) &&
+ !exists((ret = (QString(qgetenv("HOME")) + "/.tmake/" + file))))
+ return "";
+ debug_msg(1, "Generator: MSVC.NET: Found template \'%s\'", ret.toLatin1().constData());
+ return ret;
+}
+
+
+void VcprojGenerator::processPrlVariable(const QString &var, const QStringList &l)
+{
+ if(var == "QMAKE_PRL_DEFINES") {
+ QStringList &out = project->values("MSVCPROJ_DEFINES");
+ for(QStringList::ConstIterator it = l.begin(); it != l.end(); ++it) {
+ if(out.indexOf((*it)) == -1)
+ out.append((" /D " + *it));
+ }
+ } else {
+ MakefileGenerator::processPrlVariable(var, l);
+ }
+}
+
+void VcprojGenerator::outputVariables()
+{
+#if 0
+ qDebug("Generator: MSVC.NET: List of current variables:");
+ for(QMap<QString, QStringList>::ConstIterator it = project->variables().begin(); it != project->variables().end(); ++it)
+ qDebug("Generator: MSVC.NET: %s => %s", it.key().toLatin1().constData(), it.data().join(" | ").toLatin1().constData());
+#endif
+}
+
+QT_END_NAMESPACE
+
diff --git a/qmake/generators/win32/msvc_vcproj.h b/qmake/generators/win32/msvc_vcproj.h
new file mode 100644
index 0000000..9e7d725
--- /dev/null
+++ b/qmake/generators/win32/msvc_vcproj.h
@@ -0,0 +1,152 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef MSVC_VCPROJ_H
+#define MSVC_VCPROJ_H
+
+#include "winmakefile.h"
+#include "msvc_objectmodel.h"
+
+QT_BEGIN_NAMESPACE
+
+enum Target {
+ Application,
+ SharedLib,
+ StaticLib
+};
+
+struct QUuid;
+class VcprojGenerator : public Win32MakefileGenerator
+{
+ bool init_flag;
+ bool writeVcprojParts(QTextStream &);
+
+ bool writeMakefile(QTextStream &);
+ bool writeProjectMakefile();
+ void writeSubDirs(QTextStream &t);
+
+ QString findTemplate(QString file);
+ void init();
+
+public:
+ VcprojGenerator();
+ ~VcprojGenerator();
+
+ QString defaultMakefile() const;
+ QString precompH, precompHFilename, precompCPP,
+ precompObj, precompPch;
+ bool autogenPrecompCPP;
+ static bool hasBuiltinCompiler(const QString &file);
+
+ QMap<QString, QStringList> extraCompilerSources;
+ QMap<QString, QStringList> extraCompilerOutputs;
+ bool usePCH;
+
+protected:
+ virtual bool doDepends() const { return false; } //never necesary
+ virtual void processSources() { filterIncludedFiles("SOURCES"); filterIncludedFiles("GENERATED_SOURCES"); }
+ virtual QString replaceExtraCompilerVariables(const QString &, const QStringList &, const QStringList &);
+ inline QString replaceExtraCompilerVariables(const QString &val, const QString &in, const QString &out)
+ { return MakefileGenerator::replaceExtraCompilerVariables(val, in, out); }
+ virtual bool supportsMetaBuild() { return true; }
+ virtual bool supportsMergedBuilds() { return true; }
+ virtual bool mergeBuildProject(MakefileGenerator *other);
+
+ virtual bool openOutput(QFile &file, const QString &build) const;
+ virtual void processPrlVariable(const QString &, const QStringList &);
+ virtual bool findLibraries();
+ virtual void outputVariables();
+ QString fixFilename(QString ofile) const;
+
+ void initOld();
+ virtual void initProject();
+ void initConfiguration();
+ void initCompilerTool();
+ void initLinkerTool();
+ void initLibrarianTool();
+ void initResourceTool();
+ void initIDLTool();
+ void initCustomBuildTool();
+ void initPreBuildEventTools();
+ void initPostBuildEventTools();
+ void initDeploymentTool();
+ void initPreLinkEventTools();
+ void initRootFiles();
+ void initSourceFiles();
+ void initHeaderFiles();
+ void initGeneratedFiles();
+ void initTranslationFiles();
+ void initFormFiles();
+ void initResourceFiles();
+ void initLexYaccFiles();
+ void initExtraCompilerOutputs();
+
+ Target projectTarget;
+
+ // Used for single project
+ VCProjectSingleConfig vcProject;
+
+ // Holds all configurations for glue (merged) project
+ QList<VcprojGenerator*> mergedProjects;
+
+private:
+ QString fixCommandLine(DotNET version, const QString &input) const;
+ QUuid getProjectUUID(const QString &filename=QString());
+ QUuid increaseUUID(const QUuid &id);
+ friend class VCFilter;
+};
+
+inline VcprojGenerator::~VcprojGenerator()
+{ }
+
+inline QString VcprojGenerator::defaultMakefile() const
+{
+ return project->first("TARGET") + project->first("VCPROJ_EXTENSION");
+}
+
+inline bool VcprojGenerator::findLibraries()
+{
+ return Win32MakefileGenerator::findLibraries("MSVCPROJ_LIBS");
+}
+
+QT_END_NAMESPACE
+
+#endif // MSVC_VCPROJ_H
diff --git a/qmake/generators/win32/winmakefile.cpp b/qmake/generators/win32/winmakefile.cpp
new file mode 100644
index 0000000..60a27be
--- /dev/null
+++ b/qmake/generators/win32/winmakefile.cpp
@@ -0,0 +1,821 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "winmakefile.h"
+#include "option.h"
+#include "project.h"
+#include "meta.h"
+#include <qtextstream.h>
+#include <qstring.h>
+#include <qhash.h>
+#include <qregexp.h>
+#include <qstringlist.h>
+#include <qdir.h>
+#include <stdlib.h>
+
+QT_BEGIN_NAMESPACE
+
+Win32MakefileGenerator::Win32MakefileGenerator() : MakefileGenerator()
+{
+}
+
+int
+Win32MakefileGenerator::findHighestVersion(const QString &d, const QString &stem, const QString &ext)
+{
+ QString bd = Option::fixPathToLocalOS(d, true);
+ if(!exists(bd))
+ return -1;
+
+ QString dllStem = stem + QTDLL_POSTFIX;
+ QMakeMetaInfo libinfo;
+ bool libInfoRead = libinfo.readLib(bd + Option::dir_sep + dllStem);
+
+ // If the library, for which we're trying to find the highest version
+ // number, is a static library
+ if (libInfoRead && libinfo.values("QMAKE_PRL_CONFIG").contains("staticlib"))
+ return -1;
+
+ if(!project->values("QMAKE_" + stem.toUpper() + "_VERSION_OVERRIDE").isEmpty())
+ return project->values("QMAKE_" + stem.toUpper() + "_VERSION_OVERRIDE").first().toInt();
+
+ int biggest=-1;
+ if(!project->isActiveConfig("no_versionlink")) {
+ QDir dir(bd);
+ QStringList entries = dir.entryList();
+ QRegExp regx(QString("((lib)?%1([0-9]*)).(%2|prl)$").arg(dllStem).arg(ext), Qt::CaseInsensitive);
+ for(QStringList::Iterator it = entries.begin(); it != entries.end(); ++it) {
+ if(regx.exactMatch((*it))) {
+ if (!regx.cap(3).isEmpty()) {
+ bool ok = true;
+ int num = regx.cap(3).toInt(&ok);
+ biggest = qMax(biggest, (!ok ? -1 : num));
+ }
+ }
+ }
+ }
+ if(libInfoRead
+ && !libinfo.values("QMAKE_PRL_CONFIG").contains("staticlib")
+ && !libinfo.isEmpty("QMAKE_PRL_VERSION"))
+ biggest = qMax(biggest, libinfo.first("QMAKE_PRL_VERSION").replace(".", "").toInt());
+ return biggest;
+}
+
+bool
+Win32MakefileGenerator::findLibraries(const QString &where)
+{
+ QStringList &l = project->values(where);
+ QList<QMakeLocalFileName> dirs;
+ {
+ QStringList &libpaths = project->values("QMAKE_LIBDIR");
+ for(QStringList::Iterator libpathit = libpaths.begin();
+ libpathit != libpaths.end(); ++libpathit)
+ dirs.append(QMakeLocalFileName((*libpathit)));
+ }
+ for(QStringList::Iterator it = l.begin(); it != l.end();) {
+ QChar quote;
+ bool modified_opt = false, remove = false;
+ QString opt = (*it).trimmed();
+ if((opt[0] == '\'' || opt[0] == '"') && opt[(int)opt.length()-1] == opt[0]) {
+ quote = opt[0];
+ opt = opt.mid(1, opt.length()-2);
+ }
+ if(opt.startsWith("/LIBPATH:")) {
+ dirs.append(QMakeLocalFileName(opt.mid(9)));
+ } else if(opt.startsWith("-L") || opt.startsWith("/L")) {
+ QString libpath = opt.mid(2);
+ QMakeLocalFileName l(libpath);
+ if(!dirs.contains(l)) {
+ dirs.append(l);
+ modified_opt = true;
+ if (!quote.isNull()) {
+ libpath = quote + libpath + quote;
+ quote = QChar();
+ }
+ (*it) = "/LIBPATH:" + libpath;
+ } else {
+ remove = true;
+ }
+ } else if(opt.startsWith("-l") || opt.startsWith("/l")) {
+ QString lib = opt.right(opt.length() - 2), out;
+ if(!lib.isEmpty()) {
+ QString suffix;
+ if(!project->isEmpty("QMAKE_" + lib.toUpper() + "_SUFFIX"))
+ suffix = project->first("QMAKE_" + lib.toUpper() + "_SUFFIX");
+ for(QList<QMakeLocalFileName>::Iterator it = dirs.begin();
+ it != dirs.end(); ++it) {
+ QString extension;
+ int ver = findHighestVersion((*it).local(), lib);
+ if(ver > 0)
+ extension += QString::number(ver);
+ extension += suffix;
+ extension += ".lib";
+ if(QMakeMetaInfo::libExists((*it).local() + Option::dir_sep + lib) ||
+ exists((*it).local() + Option::dir_sep + lib + extension)) {
+ out = (*it).real() + Option::dir_sep + lib + extension;
+ break;
+ }
+ }
+ }
+ if(out.isEmpty())
+ out = lib + ".lib";
+ modified_opt = true;
+ (*it) = out;
+ } else if(!exists(Option::fixPathToLocalOS(opt))) {
+ QList<QMakeLocalFileName> lib_dirs;
+ QString file = opt;
+ int slsh = file.lastIndexOf(Option::dir_sep);
+ if(slsh != -1) {
+ lib_dirs.append(QMakeLocalFileName(file.left(slsh+1)));
+ file = file.right(file.length() - slsh - 1);
+ } else {
+ lib_dirs = dirs;
+ }
+ if(file.endsWith(".lib")) {
+ file = file.left(file.length() - 4);
+ if(!file.at(file.length()-1).isNumber()) {
+ QString suffix;
+ if(!project->isEmpty("QMAKE_" + file.section(Option::dir_sep, -1).toUpper() + "_SUFFIX"))
+ suffix = project->first("QMAKE_" + file.section(Option::dir_sep, -1).toUpper() + "_SUFFIX");
+ for(QList<QMakeLocalFileName>::Iterator dep_it = lib_dirs.begin(); dep_it != lib_dirs.end(); ++dep_it) {
+ QString lib_tmpl(file + "%1" + suffix + ".lib");
+ int ver = findHighestVersion((*dep_it).local(), file);
+ if(ver != -1) {
+ if(ver)
+ lib_tmpl = lib_tmpl.arg(ver);
+ else
+ lib_tmpl = lib_tmpl.arg("");
+ if(slsh != -1) {
+ QString dir = (*dep_it).real();
+ if(!dir.endsWith(Option::dir_sep))
+ dir += Option::dir_sep;
+ lib_tmpl.prepend(dir);
+ }
+ modified_opt = true;
+ (*it) = lib_tmpl;
+ break;
+ }
+ }
+ }
+ }
+ }
+ if(remove) {
+ it = l.erase(it);
+ } else {
+ if(!quote.isNull() && modified_opt)
+ (*it) = quote + (*it) + quote;
+ ++it;
+ }
+ }
+ return true;
+}
+
+void
+Win32MakefileGenerator::processPrlFiles()
+{
+ QHash<QString, bool> processed;
+ QList<QMakeLocalFileName> libdirs;
+ {
+ QStringList &libpaths = project->values("QMAKE_LIBDIR");
+ for(QStringList::Iterator libpathit = libpaths.begin(); libpathit != libpaths.end(); ++libpathit)
+ libdirs.append(QMakeLocalFileName((*libpathit)));
+ }
+ for(bool ret = false; true; ret = false) {
+ //read in any prl files included..
+ QStringList l_out;
+ QString where = "QMAKE_LIBS";
+ if(!project->isEmpty("QMAKE_INTERNAL_PRL_LIBS"))
+ where = project->first("QMAKE_INTERNAL_PRL_LIBS");
+ QStringList l = project->values(where);
+ for(QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
+ QString opt = (*it).trimmed();
+ if((opt[0] == '\'' || opt[0] == '"') && opt[(int)opt.length()-1] == opt[0])
+ opt = opt.mid(1, opt.length()-2);
+ if(opt.startsWith("/")) {
+ if(opt.startsWith("/LIBPATH:")) {
+ QMakeLocalFileName l(opt.mid(9));
+ if(!libdirs.contains(l))
+ libdirs.append(l);
+ }
+ } else if(!processed.contains(opt)) {
+ if(processPrlFile(opt)) {
+ processed.insert(opt, true);
+ ret = true;
+ } else if(QDir::isRelativePath(opt) || opt.startsWith("-l")) {
+ QString tmp;
+ if (opt.startsWith("-l"))
+ tmp = opt.mid(2);
+ else
+ tmp = opt;
+ for(QList<QMakeLocalFileName>::Iterator it = libdirs.begin(); it != libdirs.end(); ++it) {
+ QString prl = (*it).local() + Option::dir_sep + tmp;
+ // the original is used as the key
+ QString orgprl = prl;
+ if(processed.contains(prl)) {
+ break;
+ } else if(processPrlFile(prl)) {
+ processed.insert(orgprl, true);
+ ret = true;
+ break;
+ }
+ }
+ }
+ }
+ if(!opt.isEmpty())
+ l_out.append(opt);
+ }
+ if(ret)
+ l = l_out;
+ else
+ break;
+ }
+}
+
+
+void Win32MakefileGenerator::processVars()
+{
+ //If the TARGET looks like a path split it into DESTDIR and the resulting TARGET
+ if(!project->isEmpty("TARGET")) {
+ QString targ = project->first("TARGET");
+ int slsh = qMax(targ.lastIndexOf('/'), targ.lastIndexOf(Option::dir_sep));
+ if(slsh != -1) {
+ if(project->isEmpty("DESTDIR"))
+ project->values("DESTDIR").append("");
+ else if(project->first("DESTDIR").right(1) != Option::dir_sep)
+ project->values("DESTDIR") = QStringList(project->first("DESTDIR") + Option::dir_sep);
+ project->values("DESTDIR") = QStringList(project->first("DESTDIR") + targ.left(slsh+1));
+ project->values("TARGET") = QStringList(targ.mid(slsh+1));
+ }
+ }
+
+ project->values("QMAKE_ORIG_TARGET") = project->values("TARGET");
+ if (!project->values("QMAKE_INCDIR").isEmpty())
+ project->values("INCLUDEPATH") += project->values("QMAKE_INCDIR");
+
+ if (!project->values("VERSION").isEmpty()) {
+ QStringList l = project->first("VERSION").split('.');
+ if (l.size() > 0)
+ project->values("VER_MAJ").append(l[0]);
+ if (l.size() > 1)
+ project->values("VER_MIN").append(l[1]);
+ }
+
+ // TARGET_VERSION_EXT will be used to add a version number onto the target name
+ if (project->values("TARGET_VERSION_EXT").isEmpty()
+ && !project->values("VER_MAJ").isEmpty())
+ project->values("TARGET_VERSION_EXT").append(project->values("VER_MAJ").first());
+
+ if(project->isEmpty("QMAKE_COPY_FILE"))
+ project->values("QMAKE_COPY_FILE").append("$(COPY)");
+ if(project->isEmpty("QMAKE_COPY_DIR"))
+ project->values("QMAKE_COPY_DIR").append("xcopy /s /q /y /i");
+ if(project->isEmpty("QMAKE_INSTALL_FILE"))
+ project->values("QMAKE_INSTALL_FILE").append("$(COPY_FILE)");
+ if(project->isEmpty("QMAKE_INSTALL_PROGRAM"))
+ project->values("QMAKE_INSTALL_PROGRAM").append("$(COPY_FILE)");
+ if(project->isEmpty("QMAKE_INSTALL_DIR"))
+ project->values("QMAKE_INSTALL_DIR").append("$(COPY_DIR)");
+
+ fixTargetExt();
+ processRcFileVar();
+ processFileTagsVar();
+
+ QStringList &incDir = project->values("INCLUDEPATH");
+ for(QStringList::Iterator incDir_it = incDir.begin(); incDir_it != incDir.end(); ++incDir_it) {
+ if(!(*incDir_it).isEmpty())
+ (*incDir_it) = Option::fixPathToTargetOS((*incDir_it), false, false);
+ }
+ QStringList &libDir = project->values("QMAKE_LIBDIR");
+ for(QStringList::Iterator libDir_it = libDir.begin(); libDir_it != libDir.end(); ++libDir_it) {
+ if(!(*libDir_it).isEmpty())
+ (*libDir_it) = Option::fixPathToTargetOS((*libDir_it), false, false);
+ }
+}
+
+void Win32MakefileGenerator::fixTargetExt()
+{
+ if (!project->values("QMAKE_APP_FLAG").isEmpty())
+ project->values("TARGET_EXT").append(".exe");
+ else if (project->isActiveConfig("shared"))
+ project->values("TARGET_EXT").append(project->first("TARGET_VERSION_EXT") + ".dll");
+ else
+ project->values("TARGET_EXT").append(".lib");
+}
+
+void Win32MakefileGenerator::processRcFileVar()
+{
+ if (Option::qmake_mode == Option::QMAKE_GENERATE_NOTHING)
+ return;
+
+ if (((!project->values("VERSION").isEmpty())
+ && project->values("RC_FILE").isEmpty()
+ && project->values("RES_FILE").isEmpty()
+ && !project->isActiveConfig("no_generated_target_info")
+ && (project->isActiveConfig("shared") || !project->values("QMAKE_APP_FLAG").isEmpty()))
+ || !project->values("QMAKE_WRITE_DEFAULT_RC").isEmpty()){
+
+ QByteArray rcString;
+ QTextStream ts(&rcString, QFile::WriteOnly);
+
+ QStringList vers = project->values("VERSION").first().split(".");
+ for (int i = vers.size(); i < 4; i++)
+ vers += "0";
+ QString versionString = vers.join(".");
+
+ QString companyName;
+ if (!project->values("QMAKE_TARGET_COMPANY").isEmpty())
+ companyName = project->values("QMAKE_TARGET_COMPANY").join(" ");
+
+ QString description;
+ if (!project->values("QMAKE_TARGET_DESCRIPTION").isEmpty())
+ description = project->values("QMAKE_TARGET_DESCRIPTION").join(" ");
+
+ QString copyright;
+ if (!project->values("QMAKE_TARGET_COPYRIGHT").isEmpty())
+ copyright = project->values("QMAKE_TARGET_COPYRIGHT").join(" ");
+
+ QString productName;
+ if (!project->values("QMAKE_TARGET_PRODUCT").isEmpty())
+ productName = project->values("QMAKE_TARGET_PRODUCT").join(" ");
+ else
+ productName = project->values("TARGET").first();
+
+ QString originalName = project->values("TARGET").first() + project->values("TARGET_EXT").first();
+
+ ts << "# if defined(UNDER_CE)" << endl;
+ ts << "# include <winbase.h>" << endl;
+ ts << "# else" << endl;
+ ts << "# include <winver.h>" << endl;
+ ts << "# endif" << endl;
+ ts << endl;
+ ts << "VS_VERSION_INFO VERSIONINFO" << endl;
+ ts << "\tFILEVERSION " << QString(versionString).replace(".", ",") << endl;
+ ts << "\tPRODUCTVERSION " << QString(versionString).replace(".", ",") << endl;
+ ts << "\tFILEFLAGSMASK 0x3fL" << endl;
+ ts << "#ifdef _DEBUG" << endl;
+ ts << "\tFILEFLAGS VS_FF_DEBUG" << endl;
+ ts << "#else" << endl;
+ ts << "\tFILEFLAGS 0x0L" << endl;
+ ts << "#endif" << endl;
+ ts << "\tFILEOS VOS__WINDOWS32" << endl;
+ if (project->isActiveConfig("shared"))
+ ts << "\tFILETYPE VFT_DLL" << endl;
+ else
+ ts << "\tFILETYPE VFT_APP" << endl;
+ ts << "\tFILESUBTYPE 0x0L" << endl;
+ ts << "\tBEGIN" << endl;
+ ts << "\t\tBLOCK \"StringFileInfo\"" << endl;
+ ts << "\t\tBEGIN" << endl;
+ ts << "\t\t\tBLOCK \"040904B0\"" << endl;
+ ts << "\t\t\tBEGIN" << endl;
+ ts << "\t\t\t\tVALUE \"CompanyName\", \"" << companyName << "\\0\"" << endl;
+ ts << "\t\t\t\tVALUE \"FileDescription\", \"" << description << "\\0\"" << endl;
+ ts << "\t\t\t\tVALUE \"FileVersion\", \"" << versionString << "\\0\"" << endl;
+ ts << "\t\t\t\tVALUE \"LegalCopyright\", \"" << copyright << "\\0\"" << endl;
+ ts << "\t\t\t\tVALUE \"OriginalFilename\", \"" << originalName << "\\0\"" << endl;
+ ts << "\t\t\t\tVALUE \"ProductName\", \"" << productName << "\\0\"" << endl;
+ ts << "\t\t\tEND" << endl;
+ ts << "\t\tEND" << endl;
+ ts << "\tEND" << endl;
+ ts << "/* End of Version info */" << endl;
+ ts << endl;
+
+ ts.flush();
+
+
+ QString rcFilename = project->values("OUT_PWD").first()
+ + "/"
+ + project->values("TARGET").first()
+ + "_resource"
+ + ".rc";
+ QFile rcFile(QDir::cleanPath(rcFilename));
+
+ bool writeRcFile = true;
+ if (rcFile.exists() && rcFile.open(QFile::ReadOnly)) {
+ writeRcFile = rcFile.readAll() != rcString;
+ rcFile.close();
+ }
+ if (writeRcFile && rcFile.open(QFile::WriteOnly)) {
+ rcFile.write(rcString);
+ rcFile.close();
+ }
+ if (project->values("QMAKE_WRITE_DEFAULT_RC").isEmpty())
+ project->values("RC_FILE").insert(0, rcFile.fileName());
+ }
+ if (!project->values("RC_FILE").isEmpty()) {
+ if (!project->values("RES_FILE").isEmpty()) {
+ fprintf(stderr, "Both rc and res file specified.\n");
+ fprintf(stderr, "Please specify one of them, not both.");
+ exit(1);
+ }
+ QString resFile = project->values("RC_FILE").first();
+
+ // if this is a shadow build then use the absolute path of the rc file
+ if (Option::output_dir != qmake_getpwd()) {
+ QFileInfo fi(resFile);
+ project->values("RC_FILE").first() = fi.absoluteFilePath();
+ }
+
+ resFile.replace(".rc", Option::res_ext);
+ project->values("RES_FILE").prepend(fileInfo(resFile).fileName());
+ if (!project->values("OBJECTS_DIR").isEmpty())
+ if(project->isActiveConfig("staticlib"))
+ project->values("RES_FILE").first().prepend(fileInfo(project->values("DESTDIR").first()).absoluteFilePath() + Option::dir_sep);
+ else
+ project->values("RES_FILE").first().prepend(project->values("OBJECTS_DIR").first() + Option::dir_sep);
+ project->values("RES_FILE").first() = Option::fixPathToTargetOS(project->values("RES_FILE").first(), false, false);
+ project->values("POST_TARGETDEPS") += project->values("RES_FILE");
+ project->values("CLEAN_FILES") += project->values("RES_FILE");
+ }
+}
+
+void Win32MakefileGenerator::processFileTagsVar()
+{
+ QStringList tags;
+ tags << "SOURCES" << "GENERATED_SOURCES" << "DEF_FILE" << "RC_FILE"
+ << "TARGET" << "QMAKE_LIBS" << "DESTDIR" << "DLLDESTDIR" << "INCLUDEPATH";
+ if(!project->isEmpty("QMAKE_EXTRA_COMPILERS")) {
+ const QStringList &quc = project->values("QMAKE_EXTRA_COMPILERS");
+ for(QStringList::ConstIterator it = quc.begin(); it != quc.end(); ++it)
+ tags += project->values((*it)+".input");
+ }
+
+ //clean path
+ QStringList &filetags = project->values("QMAKE_FILETAGS");
+ for(int i = 0; i < tags.size(); ++i)
+ filetags += Option::fixPathToTargetOS(tags.at(i), false);
+}
+
+void Win32MakefileGenerator::writeCleanParts(QTextStream &t)
+{
+ t << "clean: compiler_clean " << var("CLEAN_DEPS");
+ {
+ const char *clean_targets[] = { "OBJECTS", "QMAKE_CLEAN", "CLEAN_FILES", 0 };
+ for(int i = 0; clean_targets[i]; ++i) {
+ const QStringList &list = project->values(clean_targets[i]);
+ const QString del_statement("-$(DEL_FILE)");
+ if(project->isActiveConfig("no_delete_multiple_files")) {
+ for(QStringList::ConstIterator it = list.begin(); it != list.end(); ++it)
+ t << "\n\t" << del_statement << " " << escapeFilePath((*it));
+ } else {
+ QString files, file;
+ const int commandlineLimit = 2047; // NT limit, expanded
+ for(QStringList::ConstIterator it = list.begin(); it != list.end(); ++it) {
+ file = " " + escapeFilePath((*it));
+ if(del_statement.length() + files.length() +
+ qMax(fixEnvVariables(file).length(), file.length()) > commandlineLimit) {
+ t << "\n\t" << del_statement << files;
+ files.clear();
+ }
+ files += file;
+ }
+ if(!files.isEmpty())
+ t << "\n\t" << del_statement << files;
+ }
+ }
+ }
+ t << endl << endl;
+
+ t << "distclean: clean";
+ {
+ const char *clean_targets[] = { "QMAKE_DISTCLEAN", 0 };
+ for(int i = 0; clean_targets[i]; ++i) {
+ const QStringList &list = project->values(clean_targets[i]);
+ const QString del_statement("-$(DEL_FILE)");
+ if(project->isActiveConfig("no_delete_multiple_files")) {
+ for(QStringList::ConstIterator it = list.begin(); it != list.end(); ++it)
+ t << "\n\t" << del_statement << " " << escapeFilePath((*it));
+ } else {
+ QString files, file;
+ const int commandlineLimit = 2047; // NT limit, expanded
+ for(QStringList::ConstIterator it = list.begin(); it != list.end(); ++it) {
+ file = " " + escapeFilePath((*it));
+ if(del_statement.length() + files.length() +
+ qMax(fixEnvVariables(file).length(), file.length()) > commandlineLimit) {
+ t << "\n\t" << del_statement << files;
+ files.clear();
+ }
+ files += file;
+ }
+ if(!files.isEmpty())
+ t << "\n\t" << del_statement << files;
+ }
+ }
+ }
+ t << "\n\t-$(DEL_FILE) $(DESTDIR_TARGET)" << endl;
+ {
+ QString ofile = Option::fixPathToTargetOS(fileFixify(Option::output.fileName()));
+ if(!ofile.isEmpty())
+ t << "\t-$(DEL_FILE) " << ofile << endl;
+ }
+ t << endl;
+}
+
+void Win32MakefileGenerator::writeIncPart(QTextStream &t)
+{
+ t << "INCPATH = ";
+
+ const QStringList &incs = project->values("INCLUDEPATH");
+ for(int i = 0; i < incs.size(); ++i) {
+ QString inc = incs.at(i);
+ inc.replace(QRegExp("\\\\$"), "");
+ inc.replace(QRegExp("\""), "");
+ if(!inc.isEmpty())
+ t << "-I" << "\"" << inc << "\" ";
+ }
+ t << "-I\"" << specdir() << "\""
+ << endl;
+}
+
+void Win32MakefileGenerator::writeStandardParts(QTextStream &t)
+{
+ t << "####### Compiler, tools and options" << endl << endl;
+ t << "CC = " << var("QMAKE_CC") << endl;
+ t << "CXX = " << var("QMAKE_CXX") << endl;
+ t << "DEFINES = "
+ << varGlue("PRL_EXPORT_DEFINES","-D"," -D"," ")
+ << varGlue("DEFINES","-D"," -D","") << endl;
+ t << "CFLAGS = " << var("QMAKE_CFLAGS") << " $(DEFINES)" << endl;
+ t << "CXXFLAGS = " << var("QMAKE_CXXFLAGS") << " $(DEFINES)" << endl;
+
+ writeIncPart(t);
+ writeLibsPart(t);
+
+ t << "QMAKE = " << (project->isEmpty("QMAKE_QMAKE") ? QString("qmake") :
+ Option::fixPathToTargetOS(var("QMAKE_QMAKE"), false)) << endl;
+ t << "IDC = " << (project->isEmpty("QMAKE_IDC") ? QString("idc") :
+ Option::fixPathToTargetOS(var("QMAKE_IDC"), false)) << endl;
+ t << "IDL = " << (project->isEmpty("QMAKE_IDL") ? QString("midl") :
+ Option::fixPathToTargetOS(var("QMAKE_IDL"), false)) << endl;
+ t << "ZIP = " << var("QMAKE_ZIP") << endl;
+ t << "DEF_FILE = " << varList("DEF_FILE") << endl;
+ t << "RES_FILE = " << varList("RES_FILE") << endl; // Not on mingw, can't see why not though...
+ t << "COPY = " << var("QMAKE_COPY") << endl;
+ t << "COPY_FILE = " << var("QMAKE_COPY_FILE") << endl;
+ t << "COPY_DIR = " << var("QMAKE_COPY_DIR") << endl;
+ t << "DEL_FILE = " << var("QMAKE_DEL_FILE") << endl;
+ t << "DEL_DIR = " << var("QMAKE_DEL_DIR") << endl;
+ t << "MOVE = " << var("QMAKE_MOVE") << endl;
+ t << "CHK_DIR_EXISTS= " << var("QMAKE_CHK_DIR_EXISTS") << endl;
+ t << "MKDIR = " << var("QMAKE_MKDIR") << endl;
+ t << "INSTALL_FILE = " << var("QMAKE_INSTALL_FILE") << endl;
+ t << "INSTALL_PROGRAM = " << var("QMAKE_INSTALL_PROGRAM") << endl;
+ t << "INSTALL_DIR = " << var("QMAKE_INSTALL_DIR") << endl;
+ t << endl;
+
+ t << "####### Output directory" << endl << endl;
+ if(!project->values("OBJECTS_DIR").isEmpty())
+ t << "OBJECTS_DIR = " << var("OBJECTS_DIR").replace(QRegExp("\\\\$"),"") << endl;
+ else
+ t << "OBJECTS_DIR = . " << endl;
+ t << endl;
+
+ t << "####### Files" << endl << endl;
+ t << "SOURCES = " << valList(escapeFilePaths(project->values("SOURCES")))
+ << " " << valList(escapeFilePaths(project->values("GENERATED_SOURCES"))) << endl;
+
+ // do this here so we can set DEST_TARGET to be the complete path to the final target if it is needed.
+ QString orgDestDir = var("DESTDIR");
+ QString destDir = Option::fixPathToTargetOS(orgDestDir, false);
+ if (orgDestDir.endsWith('/') || orgDestDir.endsWith(Option::dir_sep))
+ destDir += Option::dir_sep;
+ QString target = QString(project->first("TARGET")+project->first("TARGET_EXT"));
+ target.remove("\"");
+ project->values("DEST_TARGET").prepend(destDir + target);
+
+ writeObjectsPart(t);
+
+ writeExtraCompilerVariables(t);
+ writeExtraVariables(t);
+
+ t << "DIST = " << varList("DISTFILES") << endl;
+ t << "QMAKE_TARGET = " << var("QMAKE_ORIG_TARGET") << endl;
+ // The comment is important to maintain variable compatability with Unix
+ // Makefiles, while not interpreting a trailing-slash as a linebreak
+ t << "DESTDIR = " << escapeFilePath(destDir) << " #avoid trailing-slash linebreak" << endl;
+ t << "TARGET = " << escapeFilePath(target) << endl;
+ t << "DESTDIR_TARGET = " << escapeFilePath(var("DEST_TARGET")) << endl;
+ t << endl;
+
+ t << "####### Implicit rules" << endl << endl;
+ writeImplicitRulesPart(t);
+
+ t << "####### Build rules" << endl << endl;
+ writeBuildRulesPart(t);
+
+ if(project->isActiveConfig("shared") && !project->values("DLLDESTDIR").isEmpty()) {
+ QStringList dlldirs = project->values("DLLDESTDIR");
+ for (QStringList::Iterator dlldir = dlldirs.begin(); dlldir != dlldirs.end(); ++dlldir) {
+ t << "\n\t" << "-$(COPY_FILE) \"$(DESTDIR_TARGET)\" " << Option::fixPathToTargetOS(*dlldir, false);
+ }
+ }
+ t << endl << endl;
+
+ writeRcFilePart(t);
+
+ writeMakeQmake(t);
+
+ QStringList dist_files = fileFixify(Option::mkfile::project_files);
+ if(!project->isEmpty("QMAKE_INTERNAL_INCLUDED_FILES"))
+ dist_files += project->values("QMAKE_INTERNAL_INCLUDED_FILES");
+ if(!project->isEmpty("TRANSLATIONS"))
+ dist_files << var("TRANSLATIONS");
+ if(!project->isEmpty("FORMS")) {
+ QStringList &forms = project->values("FORMS");
+ for(QStringList::Iterator formit = forms.begin(); formit != forms.end(); ++formit) {
+ QString ui_h = fileFixify((*formit) + Option::h_ext.first());
+ if(exists(ui_h))
+ dist_files << ui_h;
+ }
+ }
+ t << "dist:" << "\n\t"
+ << "$(ZIP) " << var("QMAKE_ORIG_TARGET") << ".zip " << "$(SOURCES) $(DIST) "
+ << dist_files.join(" ") << " " << var("TRANSLATIONS") << " ";
+ if(!project->isEmpty("QMAKE_EXTRA_COMPILERS")) {
+ const QStringList &quc = project->values("QMAKE_EXTRA_COMPILERS");
+ for(QStringList::ConstIterator it = quc.begin(); it != quc.end(); ++it) {
+ const QStringList &inputs = project->values((*it)+".input");
+ for(QStringList::ConstIterator input = inputs.begin(); input != inputs.end(); ++input) {
+ t << (*input) << " ";
+ }
+ }
+ }
+ t << endl << endl;
+
+ writeCleanParts(t);
+ writeExtraTargets(t);
+ writeExtraCompilerTargets(t);
+ t << endl << endl;
+}
+
+void Win32MakefileGenerator::writeLibsPart(QTextStream &t)
+{
+ if(project->isActiveConfig("staticlib") && project->first("TEMPLATE") == "lib") {
+ t << "LIBAPP = " << var("QMAKE_LIB") << endl;
+ t << "LIBFLAGS = " << var("QMAKE_LIBFLAGS") << endl;
+ } else {
+ t << "LINK = " << var("QMAKE_LINK") << endl;
+ t << "LFLAGS = ";
+ if(!project->values("QMAKE_LIBDIR").isEmpty())
+ writeLibDirPart(t);
+ t << var("QMAKE_LFLAGS") << endl;
+ t << "LIBS = " << var("QMAKE_LIBS") << endl;
+ }
+}
+
+void Win32MakefileGenerator::writeLibDirPart(QTextStream &t)
+{
+ QStringList libDirs = project->values("QMAKE_LIBDIR");
+ for (int i = 0; i < libDirs.size(); ++i)
+ libDirs[i].remove("\"");
+ t << valGlue(libDirs,"-L\"","\" -L\"","\"") << " ";
+}
+
+void Win32MakefileGenerator::writeObjectsPart(QTextStream &t)
+{
+ t << "OBJECTS = " << valList(escapeDependencyPaths(project->values("OBJECTS"))) << endl;
+}
+
+void Win32MakefileGenerator::writeImplicitRulesPart(QTextStream &t)
+{
+ t << ".SUFFIXES:";
+ for(QStringList::Iterator cppit = Option::cpp_ext.begin(); cppit != Option::cpp_ext.end(); ++cppit)
+ t << " " << (*cppit);
+ for(QStringList::Iterator cit = Option::c_ext.begin(); cit != Option::c_ext.end(); ++cit)
+ t << " " << (*cit);
+ t << endl << endl;
+ for(QStringList::Iterator cppit = Option::cpp_ext.begin(); cppit != Option::cpp_ext.end(); ++cppit)
+ t << (*cppit) << Option::obj_ext << ":\n\t" << var("QMAKE_RUN_CXX_IMP") << endl << endl;
+ for(QStringList::Iterator cit = Option::c_ext.begin(); cit != Option::c_ext.end(); ++cit)
+ t << (*cit) << Option::obj_ext << ":\n\t" << var("QMAKE_RUN_CC_IMP") << endl << endl;
+}
+
+void Win32MakefileGenerator::writeBuildRulesPart(QTextStream &)
+{
+}
+
+void Win32MakefileGenerator::writeRcFilePart(QTextStream &t)
+{
+ if(!project->values("RC_FILE").isEmpty()) {
+ const QString res_file = project->first("RES_FILE"),
+ rc_file = fileFixify(project->first("RC_FILE"));
+ // The resource tool needs to have the same defines passed in as the compiler, since you may
+ // use these defines in the .rc file itself. Also, we need to add the _DEBUG define manually
+ // since the compiler defines this symbol by itself, and we use it in the automatically
+ // created rc file when VERSION is define the .pro file.
+ t << res_file << ": " << rc_file << "\n\t"
+ << var("QMAKE_RC") << (project->isActiveConfig("debug") ? " -D_DEBUG" : "") << " $(DEFINES) -fo " << res_file << " " << rc_file;
+ t << endl << endl;
+ }
+}
+
+QString Win32MakefileGenerator::getLibTarget()
+{
+ return QString(project->first("TARGET") + project->first("TARGET_VERSION_EXT") + ".lib");
+}
+
+QString Win32MakefileGenerator::defaultInstall(const QString &t)
+{
+ if((t != "target" && t != "dlltarget") ||
+ (t == "dlltarget" && (project->first("TEMPLATE") != "lib" || !project->isActiveConfig("shared"))) ||
+ project->first("TEMPLATE") == "subdirs")
+ return QString();
+
+ const QString root = "$(INSTALL_ROOT)";
+ QStringList &uninst = project->values(t + ".uninstall");
+ QString ret;
+ QString targetdir = Option::fixPathToTargetOS(project->first(t + ".path"), false);
+ targetdir = fileFixify(targetdir, FileFixifyAbsolute);
+ if(targetdir.right(1) != Option::dir_sep)
+ targetdir += Option::dir_sep;
+
+ if(t == "target" && project->first("TEMPLATE") == "lib") {
+ if(project->isActiveConfig("create_prl") && !project->isActiveConfig("no_install_prl") &&
+ !project->isEmpty("QMAKE_INTERNAL_PRL_FILE")) {
+ QString dst_prl = Option::fixPathToTargetOS(project->first("QMAKE_INTERNAL_PRL_FILE"));
+ int slsh = dst_prl.lastIndexOf(Option::dir_sep);
+ if(slsh != -1)
+ dst_prl = dst_prl.right(dst_prl.length() - slsh - 1);
+ dst_prl = filePrefixRoot(root, targetdir + dst_prl);
+ ret += "-$(INSTALL_FILE) \"" + project->first("QMAKE_INTERNAL_PRL_FILE") + "\" \"" + dst_prl + "\"";
+ if(!uninst.isEmpty())
+ uninst.append("\n\t");
+ uninst.append("-$(DEL_FILE) \"" + dst_prl + "\"");
+ }
+ if(project->isActiveConfig("shared") && !project->isActiveConfig("plugin")) {
+ QString lib_target = getLibTarget();
+ lib_target.remove('"');
+ QString src_targ = (project->isEmpty("DESTDIR") ? QString("$(DESTDIR)") : project->first("DESTDIR")) + lib_target;
+ QString dst_targ = filePrefixRoot(root, fileFixify(targetdir + lib_target, FileFixifyAbsolute));
+ if(!ret.isEmpty())
+ ret += "\n\t";
+ ret += QString("-$(INSTALL_FILE)") + " \"" + src_targ + "\" \"" + dst_targ + "\"";
+ if(!uninst.isEmpty())
+ uninst.append("\n\t");
+ uninst.append("-$(DEL_FILE) \"" + dst_targ + "\"");
+ }
+ }
+
+ if(t == "dlltarget" || project->values(t + ".CONFIG").indexOf("no_dll") == -1) {
+ QString src_targ = "$(DESTDIR_TARGET)";
+ QString dst_targ = filePrefixRoot(root, fileFixify(targetdir + "$(TARGET)", FileFixifyAbsolute));
+ if(!ret.isEmpty())
+ ret += "\n\t";
+ ret += QString("-$(INSTALL_FILE)") + " \"" + src_targ + "\" \"" + dst_targ + "\"";
+ if(!uninst.isEmpty())
+ uninst.append("\n\t");
+ uninst.append("-$(DEL_FILE) \"" + dst_targ + "\"");
+ }
+ return ret;
+}
+
+QString Win32MakefileGenerator::escapeFilePath(const QString &path) const
+{
+ QString ret = path;
+ if(!ret.isEmpty()) {
+ ret = unescapeFilePath(ret);
+ if(ret.contains(" "))
+ ret = "\"" + ret + "\"";
+ debug_msg(2, "EscapeFilePath: %s -> %s", path.toLatin1().constData(), ret.toLatin1().constData());
+ }
+ return ret;
+}
+
+QT_END_NAMESPACE
diff --git a/qmake/generators/win32/winmakefile.h b/qmake/generators/win32/winmakefile.h
new file mode 100644
index 0000000..c8e32f8
--- /dev/null
+++ b/qmake/generators/win32/winmakefile.h
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef WINMAKEFILE_H
+#define WINMAKEFILE_H
+
+#include "makefile.h"
+
+QT_BEGIN_NAMESPACE
+
+// In the Qt evaluation and educational version, we have a postfix in the
+// library name (e.g. qtmteval301.dll). QTDLL_POSTFIX is used for this.
+// A script modifies these lines when building eval/edu version, so be careful
+// when changing them.
+#ifndef QTDLL_POSTFIX
+#define QTDLL_POSTFIX ""
+#endif
+
+class Win32MakefileGenerator : public MakefileGenerator
+{
+public:
+ Win32MakefileGenerator();
+ ~Win32MakefileGenerator();
+protected:
+ virtual QString defaultInstall(const QString &);
+ virtual void writeCleanParts(QTextStream &t);
+ virtual void writeStandardParts(QTextStream &t);
+ virtual void writeIncPart(QTextStream &t);
+ virtual void writeLibDirPart(QTextStream &t);
+ virtual void writeLibsPart(QTextStream &t);
+ virtual void writeObjectsPart(QTextStream &t);
+ virtual void writeImplicitRulesPart(QTextStream &t);
+ virtual void writeBuildRulesPart(QTextStream &);
+ virtual QString escapeFilePath(const QString &path) const;
+
+ virtual void writeRcFilePart(QTextStream &t);
+
+ int findHighestVersion(const QString &dir, const QString &stem, const QString &ext = QLatin1String("lib"));
+ bool findLibraries(const QString &);
+ virtual bool findLibraries();
+
+ virtual void processPrlFiles();
+ virtual void processVars();
+ virtual void fixTargetExt();
+ virtual void processRcFileVar();
+ virtual void processFileTagsVar();
+ virtual QString getLibTarget();
+};
+
+inline Win32MakefileGenerator::~Win32MakefileGenerator()
+{ }
+
+inline bool Win32MakefileGenerator::findLibraries()
+{ return findLibraries("QMAKE_LIBS"); }
+
+QT_END_NAMESPACE
+
+#endif // WINMAKEFILE_H
diff --git a/qmake/generators/xmloutput.cpp b/qmake/generators/xmloutput.cpp
new file mode 100644
index 0000000..68d22e1
--- /dev/null
+++ b/qmake/generators/xmloutput.cpp
@@ -0,0 +1,340 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "xmloutput.h"
+
+QT_BEGIN_NAMESPACE
+
+XmlOutput::XmlOutput(QTextStream &file, ConverstionType type)
+ : xmlFile(file), indent("\t"), currentLevel(0), currentState(Bare), format(NewLine),
+ conversion(type)
+{
+ tagStack.clear();
+}
+
+XmlOutput::~XmlOutput()
+{
+ closeAll();
+}
+
+// Settings ------------------------------------------------------------------
+void XmlOutput::setIndentString(const QString &indentString)
+{
+ indent = indentString;
+}
+
+QString XmlOutput::indentString()
+{
+ return indent;
+}
+
+void XmlOutput::setIndentLevel(int level)
+{
+ currentLevel = level;
+}
+
+int XmlOutput::indentLevel()
+{
+ return currentLevel;
+}
+
+void XmlOutput::setState(XMLState state)
+{
+ currentState = state;
+}
+
+XmlOutput::XMLState XmlOutput::state()
+{
+ return currentState;
+}
+
+void XmlOutput::updateIndent()
+{
+ currentIndent.clear();
+ for (int i = 0; i < currentLevel; ++i)
+ currentIndent.append(indent);
+}
+
+void XmlOutput::increaseIndent()
+{
+ ++currentLevel;
+ updateIndent();
+}
+
+void XmlOutput::decreaseIndent()
+{
+ if (currentLevel)
+ --currentLevel;
+ updateIndent();
+ if (!currentLevel)
+ currentState = Bare;
+}
+
+QString XmlOutput::doConversion(const QString &text)
+{
+ if (!text.count())
+ return QString();
+ else if (conversion == NoConversion)
+ return text;
+
+ QString output;
+ if (conversion == XMLConversion) {
+
+ // this is a way to escape characters that shouldn't be converted
+ for (int i=0; i<text.count(); ++i) {
+ if (text.at(i) == QLatin1Char('&')) {
+ if ( (i + 7) < text.count() &&
+ text.at(i + 1) == QLatin1Char('#') &&
+ text.at(i + 2) == QLatin1Char('x') &&
+ text.at(i + 7) == QLatin1Char(';') ) {
+ output += text.at(i);
+ } else {
+ output += QLatin1String("&amp;");
+ }
+ } else {
+ QChar c = text.at(i);
+ if (c.unicode() < 0x20) {
+ output += QString("&#x%1;").arg(c.unicode(), 2, 16, QLatin1Char('0'));
+ } else {
+ output += text.at(i);
+ }
+ }
+ }
+ } else {
+ output = text;
+ }
+
+ if (conversion == XMLConversion) {
+ output.replace('\"', "&quot;");
+ output.replace('\'', "&apos;");
+ } else if (conversion == EscapeConversion) {
+ output.replace('\"', "\\\"");
+ output.replace('\'', "\\\'");
+ }
+ return output;
+}
+
+// Stream functions ----------------------------------------------------------
+XmlOutput& XmlOutput::operator<<(const QString& o)
+{
+ return operator<<(data(o));
+}
+
+XmlOutput& XmlOutput::operator<<(const xml_output& o)
+{
+ switch(o.xo_type) {
+ case tNothing:
+ break;
+ case tRaw:
+ addRaw(o.xo_text);
+ break;
+ case tDeclaration:
+ addDeclaration(o.xo_text, o.xo_value);
+ break;
+ case tTag:
+ newTagOpen(o.xo_text);
+ break;
+ case tCloseTag:
+ if (o.xo_value.count())
+ closeAll();
+ else if (o.xo_text.count())
+ closeTo(o.xo_text);
+ else
+ closeTag();
+ break;
+ case tAttribute:
+ addAttribute(o.xo_text, o.xo_value);
+ break;
+ case tData:
+ {
+ // Special case to be able to close tag in normal
+ // way ("</tag>", not "/>") without using addRaw()..
+ if (!o.xo_text.count()) {
+ closeOpen();
+ break;
+ }
+ QString output = doConversion(o.xo_text);
+ output.replace('\n', "\n" + currentIndent);
+ addRaw(QString("\n%1%2").arg(currentIndent).arg(output));
+ }
+ break;
+ case tComment:
+ {
+ QString output("<!--%1-->");
+ addRaw(output.arg(o.xo_text));
+ }
+ break;
+ case tCDATA:
+ {
+ QString output("<![CDATA[\n%1\n]]>");
+ addRaw(output.arg(o.xo_text));
+ }
+ break;
+ }
+ return *this;
+}
+
+
+// Output functions ----------------------------------------------------------
+void XmlOutput::newTag(const QString &tag)
+{
+ Q_ASSERT_X(tag.count(), "XmlOutput", "Cannot open an empty tag");
+ newTagOpen(tag);
+ closeOpen();
+}
+
+void XmlOutput::newTagOpen(const QString &tag)
+{
+ Q_ASSERT_X(tag.count(), "XmlOutput", "Cannot open an empty tag");
+ closeOpen();
+
+ if (format == NewLine)
+ xmlFile << endl << currentIndent;
+ xmlFile << '<' << doConversion(tag);
+ currentState = Attribute;
+ tagStack.append(tag);
+ increaseIndent(); // ---> indent
+}
+
+void XmlOutput::closeOpen()
+{
+ switch(currentState) {
+ case Bare:
+ case Tag:
+ return;
+ case Attribute:
+ break;
+ }
+ xmlFile << '>';
+ currentState = Tag;
+}
+
+void XmlOutput::closeTag()
+{
+ switch(currentState) {
+ case Bare:
+ if (tagStack.count())
+ //warn_msg(WarnLogic, "<Root>: Cannot close tag in Bare state, %d tags on stack", tagStack.count());
+ qDebug("<Root>: Cannot close tag in Bare state, %d tags on stack", tagStack.count());
+ else
+ //warn_msg(WarnLogic, "<Root>: Cannot close tag, no tags on stack");
+ qDebug("<Root>: Cannot close tag, no tags on stack");
+ return;
+ case Tag:
+ decreaseIndent(); // <--- Pre-decrease indent
+ if (format == NewLine)
+ xmlFile << endl << currentIndent;
+ xmlFile << "</" << doConversion(tagStack.last()) << '>';
+ tagStack.pop_back();
+ break;
+ case Attribute:
+ xmlFile << "/>";
+ tagStack.pop_back();
+ currentState = Tag;
+ decreaseIndent(); // <--- Post-decrease indent
+ break;
+ }
+}
+
+void XmlOutput::closeTo(const QString &tag)
+{
+ bool cont = true;
+ if (!tagStack.contains(tag) && tag != QString()) {
+ //warn_msg(WarnLogic, "<%s>: Cannot close to tag <%s>, not on stack", tagStack.last().latin1(), tag.latin1());
+ qDebug("<%s>: Cannot close to tag <%s>, not on stack", tagStack.last().toLatin1().constData(), tag.toLatin1().constData());
+ return;
+ }
+ int left = tagStack.count();
+ while (left-- && cont) {
+ cont = tagStack.last().compare(tag) != 0;
+ closeTag();
+ }
+}
+
+void XmlOutput::closeAll()
+{
+ if (!tagStack.count())
+ return;
+ closeTo(QString());
+}
+
+void XmlOutput::addDeclaration(const QString &version, const QString &encoding)
+{
+ switch(currentState) {
+ case Bare:
+ break;
+ case Tag:
+ case Attribute:
+ //warn_msg(WarnLogic, "<%s>: Cannot add declaration when not in bare state", tagStack.last().toLatin1().constData());
+ qDebug("<%s>: Cannot add declaration when not in bare state", tagStack.last().toLatin1().constData());
+ return;
+ }
+ QString outData = QString("<?xml version=\"%1\" encoding = \"%2\"?>")
+ .arg(doConversion(version))
+ .arg(doConversion(encoding));
+ addRaw(outData);
+}
+
+void XmlOutput::addRaw(const QString &rawText)
+{
+ closeOpen();
+ xmlFile << rawText;
+}
+
+void XmlOutput::addAttribute(const QString &attribute, const QString &value)
+{
+ switch(currentState) {
+ case Bare:
+ case Tag:
+ //warn_msg(WarnLogic, "<%s>: Cannot add attribute since tags not open", tagStack.last().toLatin1().constData());
+ qDebug("<%s>: Cannot add attribute (%s) since tag's not open",
+ (tagStack.count() ? tagStack.last().toLatin1().constData() : "Root"),
+ attribute.toLatin1().constData());
+ return;
+ case Attribute:
+ break;
+ }
+ if (format == NewLine)
+ xmlFile << endl;
+ xmlFile << currentIndent << doConversion(attribute) << "=\"" << doConversion(value) << "\"";
+}
+
+QT_END_NAMESPACE
diff --git a/qmake/generators/xmloutput.h b/qmake/generators/xmloutput.h
new file mode 100644
index 0000000..d0abc5e
--- /dev/null
+++ b/qmake/generators/xmloutput.h
@@ -0,0 +1,210 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef XMLOUTPUT_H
+#define XMLOUTPUT_H
+
+#include <qtextstream.h>
+#include <qstack.h>
+
+QT_BEGIN_NAMESPACE
+
+class XmlOutput
+{
+public:
+ enum ConverstionType {
+ NoConversion, // No change
+ EscapeConversion, // Use '\"'
+ XMLConversion // Use &quot;
+ };
+ enum XMLFormat {
+ NoNewLine, // No new lines, unless added manually
+ NewLine // All properties & tags indented on new lines
+ };
+ enum XMLState {
+ Bare, // Not in tag or attribute
+ Tag, // <tagname attribute1="value"
+ Attribute // attribute2="value">
+ };
+ enum XMLType {
+ tNothing, // No XML output, and not state change
+ tRaw, // Raw text (no formating)
+ tDeclaration, // <?xml version="x.x" encoding="xxx"?>
+ tTag, // <tagname attribute1="value"
+ tCloseTag, // Closes an open tag
+ tAttribute, // attribute2="value">
+ tData, // Tag data (formating done)
+ tComment, // <!-- Comment -->
+ tCDATA // <![CDATA[ ... ]]>
+ };
+
+ XmlOutput(QTextStream &file, ConverstionType type = XMLConversion);
+ ~XmlOutput();
+
+ // Settings
+ void setIndentString(const QString &indentString);
+ QString indentString();
+ void setIndentLevel(int level);
+ int indentLevel();
+ void setState(XMLState state);
+ XMLState state();
+
+
+ struct xml_output {
+ XMLType xo_type; // Type of struct instance
+ QString xo_text; // Tag/Attribute name/xml version
+ QString xo_value; // Value of attributes/xml encoding
+
+ xml_output(XMLType type, const QString &text, const QString &value)
+ : xo_type(type), xo_text(text), xo_value(value) {}
+ xml_output(const xml_output &xo)
+ : xo_type(xo.xo_type), xo_text(xo.xo_text), xo_value(xo.xo_value) {}
+ };
+
+ // Streams
+ XmlOutput& operator<<(const QString& o);
+ XmlOutput& operator<<(const xml_output& o);
+
+private:
+ void increaseIndent();
+ void decreaseIndent();
+ void updateIndent();
+
+ QString doConversion(const QString &text);
+
+ // Output functions
+ void newTag(const QString &tag);
+ void newTagOpen(const QString &tag);
+ void closeOpen();
+ void closeTag();
+ void closeTo(const QString &tag);
+ void closeAll();
+
+ void addDeclaration(const QString &version, const QString &encoding);
+ void addRaw(const QString &rawText);
+ void addAttribute(const QString &attribute, const QString &value);
+ void addData(const QString &data);
+
+ // Data
+ QTextStream &xmlFile;
+ QString indent;
+
+ QString currentIndent;
+ int currentLevel;
+ XMLState currentState;
+
+ XMLFormat format;
+ ConverstionType conversion;
+ QStack<QString> tagStack;
+};
+
+inline XmlOutput::xml_output noxml()
+{
+ return XmlOutput::xml_output(XmlOutput::tNothing, QString(), QString());
+}
+
+inline XmlOutput::xml_output raw(const QString &rawText)
+{
+ return XmlOutput::xml_output(XmlOutput::tRaw, rawText, QString());
+}
+
+inline XmlOutput::xml_output declaration(const QString &version = QString("1.0"),
+ const QString &encoding = QString())
+{
+ return XmlOutput::xml_output(XmlOutput::tDeclaration, version, encoding);
+}
+
+inline XmlOutput::xml_output decl(const QString &version = QString("1.0"),
+ const QString &encoding = QString())
+{
+ return declaration(version, encoding);
+}
+
+inline XmlOutput::xml_output tag(const QString &name)
+{
+ return XmlOutput::xml_output(XmlOutput::tTag, name, QString());
+}
+
+inline XmlOutput::xml_output closetag()
+{
+ return XmlOutput::xml_output(XmlOutput::tCloseTag, QString(), QString());
+}
+
+inline XmlOutput::xml_output closetag(const QString &toTag)
+{
+ return XmlOutput::xml_output(XmlOutput::tCloseTag, toTag, QString());
+}
+
+inline XmlOutput::xml_output closeall()
+{
+ return XmlOutput::xml_output(XmlOutput::tCloseTag, QString(), QString("all"));
+}
+
+inline XmlOutput::xml_output attribute(const QString &name,
+ const QString &value)
+{
+ return XmlOutput::xml_output(XmlOutput::tAttribute, name, value);
+}
+
+inline XmlOutput::xml_output attr(const QString &name,
+ const QString &value)
+{
+ return attribute(name, value);
+}
+
+inline XmlOutput::xml_output data(const QString &text = QString())
+{
+ return XmlOutput::xml_output(XmlOutput::tData, text, QString());
+}
+
+inline XmlOutput::xml_output comment(const QString &text)
+{
+ return XmlOutput::xml_output(XmlOutput::tComment, text, QString());
+}
+
+inline XmlOutput::xml_output cdata(const QString &text)
+{
+ return XmlOutput::xml_output(XmlOutput::tCDATA, text, QString());
+}
+
+QT_END_NAMESPACE
+
+#endif // XMLOUTPUT_H