From 5582851c33a768cfe63a418da0bf0df69260f227 Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Mon, 22 Dec 2014 14:54:08 +0100 Subject: [PATCH] turn off nmake inference rule generation on detected conflicts When there are source files with the same file name in different directories of the project, then nmake's inference rules might pick up the wrong source file. Note that this even happens when only one of those files is in SOURCES. The existence of conflicting file names is enough to cause hard-to-find build failures. The usual work-around for this situation is CONFIG+=no_batch. This is now done automatically when a conflict situation is detected and a warning message is printed. Task-number: QTBUG-13496 Change-Id: Icd81027407d3d489dbc50231e5ed8bcb91f8d2bc Reviewed-by: Oswald Buddenhagen Reviewed-by: Joerg Bornemann --- qmake/generators/win32/msvc_nmake.cpp | 53 ++++++++++++++++++++++++--- qmake/generators/win32/msvc_nmake.h | 1 + 2 files changed, 48 insertions(+), 6 deletions(-) diff --git a/qmake/generators/win32/msvc_nmake.cpp b/qmake/generators/win32/msvc_nmake.cpp index 37e247c5cb..e6170e4825 100644 --- a/qmake/generators/win32/msvc_nmake.cpp +++ b/qmake/generators/win32/msvc_nmake.cpp @@ -37,6 +37,7 @@ #include #include +#include #include #include @@ -425,6 +426,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:"; @@ -434,12 +446,9 @@ 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"); - - QSet source_directories; + bool useInferenceRules = !project->isActiveConfig("no_batch"); + QSet 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++) { @@ -462,6 +471,38 @@ void NmakeMakefileGenerator::writeImplicitRulesPart(QTextStream &t) } } + // 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 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; diff --git a/qmake/generators/win32/msvc_nmake.h b/qmake/generators/win32/msvc_nmake.h index 753223b98e..c514fa4452 100644 --- a/qmake/generators/win32/msvc_nmake.h +++ b/qmake/generators/win32/msvc_nmake.h @@ -48,6 +48,7 @@ class NmakeMakefileGenerator : public Win32MakefileGenerator void writeLinkCommand(QTextStream &t, const QString &extraFlags = QString(), const QString &extraInlineFileContent = QString()); int msvcVersion() const; void init(); + static QStringList sourceFilesForImplicitRulesFilter(); protected: virtual void writeSubMakeCall(QTextStream &t, const QString &callPrefix,