summaryrefslogtreecommitdiffstats
path: root/qmake/generators/win32/msvc_nmake.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'qmake/generators/win32/msvc_nmake.cpp')
-rw-r--r--qmake/generators/win32/msvc_nmake.cpp173
1 files changed, 99 insertions, 74 deletions
diff --git a/qmake/generators/win32/msvc_nmake.cpp b/qmake/generators/win32/msvc_nmake.cpp
index 758db337ea..740c8c4d13 100644
--- a/qmake/generators/win32/msvc_nmake.cpp
+++ b/qmake/generators/win32/msvc_nmake.cpp
@@ -1,7 +1,7 @@
/****************************************************************************
**
-** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
**
** This file is part of the qmake application of the Qt Toolkit.
**
@@ -10,9 +10,9 @@
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -23,8 +23,8 @@
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
@@ -36,8 +36,9 @@
#include "cesdkhandler.h"
#include <qregexp.h>
-#include <qhash.h>
#include <qdir.h>
+#include <qdiriterator.h>
+#include <qset.h>
#include <windows/registry_p.h>
@@ -55,7 +56,7 @@ static QString nmakePathList(const QStringList &list)
.replace('#', QStringLiteral("^#")).replace('$', QStringLiteral("$$"));
}
-NmakeMakefileGenerator::NmakeMakefileGenerator() : Win32MakefileGenerator(), init_flag(false), usePCH(false)
+NmakeMakefileGenerator::NmakeMakefileGenerator() : Win32MakefileGenerator(), usePCH(false)
{
}
@@ -160,10 +161,7 @@ NmakeMakefileGenerator::writeMakefile(QTextStream &t)
QString windowsPath;
if (isPhone) {
- if (targetVer == "WP80") // ### Windows Phone 8.0, remove in Qt 5.4
- windowsPath = "Microsoft\\Microsoft SDKs\\WindowsPhone\\v";
- else
- windowsPath = "Microsoft\\Microsoft SDKs\\WindowsPhoneApp\\v";
+ windowsPath = "Microsoft\\Microsoft SDKs\\WindowsPhoneApp\\v";
} else {
windowsPath = "Microsoft\\Microsoft SDKs\\Windows\\v";
}
@@ -184,8 +182,6 @@ NmakeMakefileGenerator::writeMakefile(QTextStream &t)
QStringList binDirs;
if (isPhone) {
QString sdkDir = vcInstallDir;
- if (targetVer == "WP80")
- sdkDir += QStringLiteral("/WPSDK/") + targetVer;
if (!QDir(sdkDir).exists()) {
fprintf(stderr, "Failed to find the Windows Phone SDK in %s.\n"
"Check that it is properly installed.\n",
@@ -256,23 +252,21 @@ QString NmakeMakefileGenerator::defaultInstall(const QString &t)
const QString root = "$(INSTALL_ROOT)";
ProStringList &uninst = project->values(ProKey(t + ".uninstall"));
- QString targetdir = Option::fixPathToTargetOS(project->first(ProKey(t + ".path")).toQString(), false);
- targetdir = fileFixify(targetdir, FileFixifyAbsolute);
+ QString targetdir = fileFixify(project->first(ProKey(t + ".path")).toQString(), FileFixifyAbsolute);
if(targetdir.right(1) != Option::dir_sep)
targetdir += Option::dir_sep;
if (project->isActiveConfig("debug_info")) {
if (t == "dlltarget" || project->values(ProKey(t + ".CONFIG")).indexOf("no_dll") == -1) {
QString pdb_target = getPdbTarget();
- pdb_target.remove('"');
QString src_targ = (project->isEmpty("DESTDIR") ? QString("$(DESTDIR)") : project->first("DESTDIR")) + pdb_target;
QString dst_targ = filePrefixRoot(root, fileFixify(targetdir + pdb_target, FileFixifyAbsolute));
if(!ret.isEmpty())
ret += "\n\t";
- ret += QString("-$(INSTALL_FILE)") + " \"" + src_targ + "\" \"" + dst_targ + "\"";
+ ret += QString("-$(INSTALL_FILE) ") + escapeFilePath(src_targ) + ' ' + escapeFilePath(dst_targ);
if(!uninst.isEmpty())
uninst.append("\n\t");
- uninst.append("-$(DEL_FILE) \"" + dst_targ + "\"");
+ uninst.append("-$(DEL_FILE) " + escapeFilePath(dst_targ));
}
}
@@ -282,10 +276,6 @@ QString NmakeMakefileGenerator::defaultInstall(const QString &t)
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))
@@ -302,9 +292,12 @@ void NmakeMakefileGenerator::writeNmakeParts(QTextStream &t)
// precompiled header
if(usePCH) {
- QString precompRule = QString("-c -Yc -Fp%1 -Fo%2").arg(precompPch).arg(precompObj);
- t << precompObj << ": " << precompH << " " << escapeDependencyPaths(findDependencies(precompH)).join(" \\\n\t\t")
- << "\n\t$(CXX) " + precompRule +" $(CXXFLAGS) $(INCPATH) -TP " << precompH << endl << endl;
+ QString precompRule = QString("-c -Yc -Fp%1 -Fo%2")
+ .arg(escapeFilePath(precompPch), escapeFilePath(precompObj));
+ t << escapeDependencyPath(precompObj) << ": " << escapeDependencyPath(precompH) << ' '
+ << escapeDependencyPaths(findDependencies(precompH)).join(" \\\n\t\t")
+ << "\n\t$(CXX) " + precompRule +" $(CXXFLAGS) $(INCPATH) -TP "
+ << escapeFilePath(precompH) << endl << endl;
}
}
@@ -315,10 +308,9 @@ QString NmakeMakefileGenerator::var(const ProKey &value) const
|| value == "QMAKE_RUN_CXX_IMP"
|| value == "QMAKE_RUN_CXX")) {
QFileInfo precompHInfo(fileInfo(precompH));
+ QString precompH_f = escapeFilePath(precompHInfo.fileName());
QString precompRule = QString("-c -FI%1 -Yu%2 -Fp%3")
- .arg(precompHInfo.fileName())
- .arg(precompHInfo.fileName())
- .arg(precompPch);
+ .arg(precompH_f, precompH_f, escapeFilePath(precompPch));
QString p = MakefileGenerator::var(value);
p.replace("-c", precompRule);
// Cannot use -Gm with -FI & -Yu, as this gives an
@@ -339,10 +331,6 @@ QString NmakeMakefileGenerator::var(const ProKey &value) const
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");
@@ -352,16 +340,6 @@ void NmakeMakefileGenerator::init()
MakefileGenerator::init();
if(project->values("MAKEFILE").isEmpty())
project->values("MAKEFILE").append("Makefile");
- 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;
}
@@ -369,9 +347,7 @@ void NmakeMakefileGenerator::init()
processVars();
- if (!project->values("RES_FILE").isEmpty()) {
- project->values("QMAKE_LIBS") += escapeFilePaths(project->values("RES_FILE"));
- }
+ project->values("QMAKE_LIBS") += project->values("RES_FILE");
if (!project->values("DEF_FILE").isEmpty()) {
QString defFileName = fileFixify(project->first("DEF_FILE").toQString());
@@ -412,6 +388,7 @@ void NmakeMakefileGenerator::init()
ProString version = project->first("TARGET_VERSION_EXT");
if(project->isActiveConfig("shared")) {
project->values("QMAKE_CLEAN").append(project->first("DESTDIR") + project->first("TARGET") + version + ".exp");
+ project->values("QMAKE_DISTCLEAN").append(project->first("DESTDIR") + project->first("TARGET") + version + ".lib");
}
if (project->isActiveConfig("debug_info")) {
QString pdbfile = project->first("DESTDIR") + project->first("TARGET") + version + ".pdb";
@@ -430,6 +407,17 @@ void NmakeMakefileGenerator::init()
}
}
+QStringList NmakeMakefileGenerator::sourceFilesForImplicitRulesFilter()
+{
+ QStringList filter;
+ const QChar wildcard = QLatin1Char('*');
+ foreach (const QString &ext, Option::c_ext)
+ filter << wildcard + ext;
+ foreach (const QString &ext, Option::cpp_ext)
+ filter << wildcard + ext;
+ return filter;
+}
+
void NmakeMakefileGenerator::writeImplicitRulesPart(QTextStream &t)
{
t << ".SUFFIXES:";
@@ -439,20 +427,17 @@ void NmakeMakefileGenerator::writeImplicitRulesPart(QTextStream &t)
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.insert(".", (void*)1);
+ bool useInferenceRules = !project->isActiveConfig("no_batch");
+ QSet<QString> source_directories;
+ if (useInferenceRules) {
+ source_directories.insert(".");
static const char * const directories[] = { "UI_SOURCES_DIR", "UI_DIR", 0 };
for (int y = 0; directories[y]; y++) {
QString dirTemp = project->first(directories[y]).toQString();
if (dirTemp.endsWith("\\"))
dirTemp.truncate(dirTemp.length()-1);
if(!dirTemp.isEmpty())
- source_directories.insert(dirTemp, (void*)1);
+ source_directories.insert(dirTemp);
}
static const char * const srcs[] = { "SOURCES", "GENERATED_SOURCES", 0 };
for (int x = 0; srcs[x]; x++) {
@@ -462,23 +447,59 @@ void NmakeMakefileGenerator::writeImplicitRulesPart(QTextStream &t)
if((*sit).indexOf(sep) == -1)
sep = "/";
QString dir = (*sit).toQString().section(sep, 0, -2);
- if(!dir.isEmpty() && !source_directories[dir])
- source_directories.insert(dir, (void*)1);
+ if (!dir.isEmpty())
+ source_directories.insert(dir);
}
}
- for(QHash<QString, void*>::Iterator it(source_directories.begin()); it != source_directories.end(); ++it) {
- if(it.key().isEmpty())
+ // nmake's inference rules might pick up the wrong files when encountering source files with
+ // the same name in different directories. In this situation, turn inference rules off.
+ QHash<QString, QString> fileNames;
+ bool duplicatesFound = false;
+ const QStringList sourceFilesFilter = sourceFilesForImplicitRulesFilter();
+ QStringList fixifiedSourceDirs = fileFixify(source_directories.toList(), FileFixifyAbsolute);
+ fixifiedSourceDirs.removeDuplicates();
+ foreach (const QString &sourceDir, fixifiedSourceDirs) {
+ QDirIterator dit(sourceDir, sourceFilesFilter, QDir::Files | QDir::NoDotAndDotDot);
+ while (dit.hasNext()) {
+ dit.next();
+ QString &duplicate = fileNames[dit.fileName()];
+ if (duplicate.isNull()) {
+ duplicate = dit.filePath();
+ } else {
+ warn_msg(WarnLogic, "%s conflicts with %s", qPrintable(duplicate),
+ qPrintable(dit.filePath()));
+ duplicatesFound = true;
+ }
+ }
+ }
+ if (duplicatesFound) {
+ useInferenceRules = false;
+ warn_msg(WarnLogic, "Automatically turning off nmake's inference rules. (CONFIG += no_batch)");
+ }
+ }
+
+ if (useInferenceRules) {
+ // 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");
+
+ foreach (const QString &sourceDir, source_directories) {
+ if (sourceDir.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$<\n<<\n\n";
+ t << '{' << escapeDependencyPath(sourceDir) << '}' << (*cppit)
+ << '{' << escapeDependencyPath(objDir) << '}' << Option::obj_ext << "::\n\t"
+ << var("QMAKE_RUN_CXX_IMP_BATCH").replace(QRegExp("\\$@"), fileVar("OBJECTS_DIR"))
+ << "\n\t$<\n<<\n\n";
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$<\n<<\n\n";
+ t << '{' << escapeDependencyPath(sourceDir) << '}' << (*cit)
+ << '{' << escapeDependencyPath(objDir) << '}' << Option::obj_ext << "::\n\t"
+ << var("QMAKE_RUN_CC_IMP_BATCH").replace(QRegExp("\\$@"), fileVar("OBJECTS_DIR"))
+ << "\n\t$<\n<<\n\n";
}
} else {
for(QStringList::Iterator cppit = Option::cpp_ext.begin(); cppit != Option::cpp_ext.end(); ++cppit)
@@ -494,8 +515,9 @@ void NmakeMakefileGenerator::writeBuildRulesPart(QTextStream &t)
const ProString templateName = project->first("TEMPLATE");
t << "first: all\n";
- t << "all: " << fileFixify(Option::output.fileName()) << " " << varGlue("ALL_DEPS"," "," "," ") << "$(DESTDIR_TARGET)\n\n";
- t << "$(DESTDIR_TARGET): " << var("PRE_TARGETDEPS") << " $(OBJECTS) " << var("POST_TARGETDEPS");
+ t << "all: " << escapeDependencyPath(fileFixify(Option::output.fileName()))
+ << ' ' << depVar("ALL_DEPS") << " $(DESTDIR_TARGET)\n\n";
+ t << "$(DESTDIR_TARGET): " << depVar("PRE_TARGETDEPS") << " $(OBJECTS) " << depVar("POST_TARGETDEPS");
if(!project->isEmpty("QMAKE_PRE_LINK"))
t << "\n\t" <<var("QMAKE_PRE_LINK");
@@ -519,12 +541,12 @@ void NmakeMakefileGenerator::writeBuildRulesPart(QTextStream &t)
if (linkerSupportsEmbedding) {
extraLFlags = "/MANIFEST:embed";
} else {
- manifest = escapeFilePath(target + ".embed.manifest");
- extraLFlags += "/MANIFEST /MANIFESTFILE:" + manifest;
+ manifest = target + ".embed.manifest";
+ extraLFlags += "/MANIFEST /MANIFESTFILE:" + escapeFilePath(manifest);
project->values("QMAKE_CLEAN") << manifest;
}
} else {
- manifest = escapeFilePath(fileFixify(manifest));
+ manifest = fileFixify(manifest);
}
const QString resourceId = (templateName == "app") ? "1" : "2";
@@ -532,16 +554,19 @@ void NmakeMakefileGenerator::writeBuildRulesPart(QTextStream &t)
if (incrementalLinking && !linkerSupportsEmbedding) {
// Link a resource that contains the manifest without modifying the exe/dll after linking.
- QString manifest_rc = escapeFilePath(target + "_manifest.rc");
- QString manifest_res = escapeFilePath(target + "_manifest.res");
- QString manifest_bak = escapeFilePath(target + "_manifest.bak");
+ QString manifest_rc = target + "_manifest.rc";
+ QString manifest_res = target + "_manifest.res";
project->values("QMAKE_CLEAN") << manifest_rc << manifest_res;
+ manifest_rc = escapeFilePath(manifest_rc);
+ manifest_res = escapeFilePath(manifest_res);
t << "\n\techo " << resourceId
<< " /* CREATEPROCESS_MANIFEST_RESOURCE_ID */ 24 /* RT_MANIFEST */ "
- << cQuoted(unescapeFilePath(manifest)) << ">" << manifest_rc;
+ << cQuoted(manifest) << '>' << manifest_rc;
if (generateManifest) {
+ manifest = escapeFilePath(manifest);
+ QString manifest_bak = escapeFilePath(target + "_manifest.bak");
t << "\n\tif not exist $(DESTDIR_TARGET) if exist " << manifest
<< " del " << manifest;
t << "\n\tif exist " << manifest << " copy /Y " << manifest << ' ' << manifest_bak;
@@ -563,7 +588,7 @@ void NmakeMakefileGenerator::writeBuildRulesPart(QTextStream &t)
t << "\n\t";
writeLinkCommand(t, extraLFlags);
if (!linkerSupportsEmbedding) {
- t << "\n\tmt.exe /nologo /manifest " << manifest
+ t << "\n\tmt.exe /nologo /manifest " << escapeFilePath(manifest)
<< " /outputresource:$(DESTDIR_TARGET);" << resourceId;
}
}
@@ -576,7 +601,7 @@ void NmakeMakefileGenerator::writeBuildRulesPart(QTextStream &t)
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)";
+ t << "\n\tsigntool sign /F " << escapeFilePath(signature) << " $(DESTDIR_TARGET)";
}
if(!project->isEmpty("QMAKE_POST_LINK")) {
t << "\n\t" << var("QMAKE_POST_LINK");