diff options
author | axis <qt-info@nokia.com> | 2009-04-24 11:34:15 (GMT) |
---|---|---|
committer | axis <qt-info@nokia.com> | 2009-04-24 11:34:15 (GMT) |
commit | 8f427b2b914d5b575a4a7c0ed65d2fb8f45acc76 (patch) | |
tree | a17e1a767a89542ab59907462206d7dcf2e504b2 /qmake/generators/win32 | |
download | Qt-8f427b2b914d5b575a4a7c0ed65d2fb8f45acc76.zip Qt-8f427b2b914d5b575a4a7c0ed65d2fb8f45acc76.tar.gz Qt-8f427b2b914d5b575a4a7c0ed65d2fb8f45acc76.tar.bz2 |
Long live Qt for S60!
Diffstat (limited to 'qmake/generators/win32')
-rw-r--r-- | qmake/generators/win32/borland_bmake.cpp | 177 | ||||
-rw-r--r-- | qmake/generators/win32/borland_bmake.h | 68 | ||||
-rw-r--r-- | qmake/generators/win32/mingw_make.cpp | 460 | ||||
-rw-r--r-- | qmake/generators/win32/mingw_make.h | 87 | ||||
-rw-r--r-- | qmake/generators/win32/msvc_dsp.cpp | 1222 | ||||
-rw-r--r-- | qmake/generators/win32/msvc_dsp.h | 122 | ||||
-rw-r--r-- | qmake/generators/win32/msvc_nmake.cpp | 322 | ||||
-rw-r--r-- | qmake/generators/win32/msvc_nmake.h | 76 | ||||
-rw-r--r-- | qmake/generators/win32/msvc_objectmodel.cpp | 2657 | ||||
-rw-r--r-- | qmake/generators/win32/msvc_objectmodel.h | 1078 | ||||
-rw-r--r-- | qmake/generators/win32/msvc_vcproj.cpp | 1800 | ||||
-rw-r--r-- | qmake/generators/win32/msvc_vcproj.h | 152 | ||||
-rw-r--r-- | qmake/generators/win32/winmakefile.cpp | 821 | ||||
-rw-r--r-- | qmake/generators/win32/winmakefile.h | 96 |
14 files changed, 9138 insertions, 0 deletions
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..0fc309e --- /dev/null +++ b/qmake/generators/win32/msvc_dsp.cpp @@ -0,0 +1,1222 @@ +/**************************************************************************** +** +** 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 defined(Q_CC_MWERKS) && defined(Q_OS_WIN32) + QPopen procPipe; + if( procPipe.init(dep_cmd.toLatin1().constData(), "r") ) { + QString indeps; + while(true) { + int read_in = procPipe.fread(buff, 255); + if ( !read_in ) + break; + indeps += QByteArray(buff, read_in); + } + if(!indeps.isEmpty()) + step.deps += config->fileFixify(indeps.replace('\n', ' ').simplified().split(' ')); + } +#else + 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(' ')); + } +#endif + } + } + + + 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..6e36c47 --- /dev/null +++ b/qmake/generators/win32/msvc_objectmodel.cpp @@ -0,0 +1,2657 @@ +/**************************************************************************** +** +** 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 defined(Q_CC_MWERKS) && defined(Q_OS_WIN32) + QPopen procPipe; + if( procPipe.init(dep_cmd.toLatin1().constData(), "r") ) { + QString indeps; + while(true) { + int read_in = procPipe.fread(buff, 255); + if ( !read_in ) + break; + indeps += QByteArray(buff, read_in); + } + 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); + } + } + } +#else + 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); + } + } + } +#endif + } + } + 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..7e703c2 --- /dev/null +++ b/qmake/generators/win32/msvc_vcproj.cpp @@ -0,0 +1,1800 @@ +/**************************************************************************** +** +** 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("
")); + + 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 defined(Q_CC_MWERKS) && defined(Q_OS_WIN32) + QPopen procPipe; + if( procPipe.init(dep_cmd.toLatin1().constData(), "r") ) { + QString indeps; + while(true) { + int read_in = procPipe.fread(buff, 255); + if ( !read_in ) + break; + indeps += QByteArray(buff, read_in); + } + if(!indeps.isEmpty()) + deps += fileFixify(indeps.replace('\n', ' ').simplified().split(' ')); + } +#else + 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(' ')); + } +#endif + } + } + 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 |