From e75aed1a96e626f079af307c5604ddf9054ecafc Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Wed, 31 Jul 2019 13:53:24 +0200 Subject: Warn about conflicting DESTDIR/TARGET combination in debug_and_release If a project has DESTDIR and TARGET set to fixed values, then the target paths conflict when doing debug_and_release builds. With this change we're detecting this situation and yield a warning. Fixes: QTBUG-2736 Change-Id: Ib163db3463322792ab9fa5b997285ac9fc9819ab Reviewed-by: Kai Koehne --- qmake/generators/makefile.cpp | 9 +++++ qmake/generators/makefile.h | 1 + qmake/generators/metamakefile.cpp | 39 ++++++++++++++++++++++ qmake/generators/win32/winmakefile.cpp | 5 +++ qmake/generators/win32/winmakefile.h | 3 ++ .../conflicting_targets/conflicting_targets.pro | 5 +++ .../qmake/testdata/conflicting_targets/main.cpp | 4 +++ tests/auto/tools/qmake/tst_qmake.cpp | 15 +++++++++ 8 files changed, 81 insertions(+) create mode 100644 tests/auto/tools/qmake/testdata/conflicting_targets/conflicting_targets.pro create mode 100644 tests/auto/tools/qmake/testdata/conflicting_targets/main.cpp diff --git a/qmake/generators/makefile.cpp b/qmake/generators/makefile.cpp index 2082bd6dc3..59cae332d8 100644 --- a/qmake/generators/makefile.cpp +++ b/qmake/generators/makefile.cpp @@ -3456,4 +3456,13 @@ QString MakefileGenerator::shellQuote(const QString &str) return isWindowsShell() ? IoUtils::shellQuoteWin(str) : IoUtils::shellQuoteUnix(str); } +/* + * Returns the name of the variable that contains the fully resolved target + * (including DESTDIR) of this generator. + */ +ProKey MakefileGenerator::fullTargetVariable() const +{ + return "TARGET"; +} + QT_END_NAMESPACE diff --git a/qmake/generators/makefile.h b/qmake/generators/makefile.h index ac1d5abb11..45250a6aa2 100644 --- a/qmake/generators/makefile.h +++ b/qmake/generators/makefile.h @@ -276,6 +276,7 @@ public: virtual bool openOutput(QFile &, const QString &build) const; bool isWindowsShell() const { return Option::dir_sep == QLatin1String("\\"); } QString shellQuote(const QString &str); + virtual ProKey fullTargetVariable() const; }; Q_DECLARE_TYPEINFO(MakefileGenerator::Compiler, Q_MOVABLE_TYPE); Q_DECLARE_OPERATORS_FOR_FLAGS(MakefileGenerator::FileFixifyTypes) diff --git a/qmake/generators/metamakefile.cpp b/qmake/generators/metamakefile.cpp index 705ad7008a..22a72100f7 100644 --- a/qmake/generators/metamakefile.cpp +++ b/qmake/generators/metamakefile.cpp @@ -33,6 +33,10 @@ #include "project.h" #include "cachekeys.h" +#include +#include +#include + #define BUILDSMETATYPE 1 #define SUBDIRSMETATYPE 2 @@ -58,6 +62,7 @@ private: void clearBuilds(); MakefileGenerator *processBuild(const ProString &); void accumulateVariableFromBuilds(const ProKey &name, Build *build) const; + void checkForConflictingTargets() const; public: @@ -186,6 +191,7 @@ BuildsMetaMakefileGenerator::write() if(!build->makefile) { ret = false; } else if(build == glue) { + checkForConflictingTargets(); accumulateVariableFromBuilds("QMAKE_INTERNAL_INCLUDED_FILES", build); ret = build->makefile->writeProjectMakefile(); } else { @@ -239,6 +245,39 @@ void BuildsMetaMakefileGenerator::accumulateVariableFromBuilds(const ProKey &nam values.removeDuplicates(); } +void BuildsMetaMakefileGenerator::checkForConflictingTargets() const +{ + if (makefiles.count() < 3) { + // Checking for conflicts only makes sense if we have more than one BUILD, + // and the last entry in makefiles is the "glue" Build. + return; + } + using TargetInfo = std::pair; + QVector targets; + const int last = makefiles.count() - 1; + targets.resize(last); + for (int i = 0; i < last; ++i) { + Build *b = makefiles.at(i); + auto mkf = b->makefile; + auto prj = mkf->projectFile(); + targets[i] = std::make_pair(b, prj->first(mkf->fullTargetVariable())); + } + std::stable_sort(targets.begin(), targets.end(), + [](const TargetInfo &lhs, const TargetInfo &rhs) + { + return lhs.second < rhs.second; + }); + for (auto prev = targets.begin(), it = std::next(prev); it != targets.end(); ++prev, ++it) { + if (prev->second == it->second) { + warn_msg(WarnLogic, "Targets of builds '%s' and '%s' conflict: %s.", + qPrintable(prev->first->build), + qPrintable(it->first->build), + qPrintable(prev->second.toQString())); + break; + } + } +} + class SubdirsMetaMakefileGenerator : public MetaMakefileGenerator { protected: diff --git a/qmake/generators/win32/winmakefile.cpp b/qmake/generators/win32/winmakefile.cpp index b79fd8f250..613a5a6a89 100644 --- a/qmake/generators/win32/winmakefile.cpp +++ b/qmake/generators/win32/winmakefile.cpp @@ -815,4 +815,9 @@ QString Win32MakefileGenerator::getManifestFileForRcFile() const return QString(); } +ProKey Win32MakefileGenerator::fullTargetVariable() const +{ + return "DEST_TARGET"; +} + QT_END_NAMESPACE diff --git a/qmake/generators/win32/winmakefile.h b/qmake/generators/win32/winmakefile.h index 8eb633fdfa..09984fe355 100644 --- a/qmake/generators/win32/winmakefile.h +++ b/qmake/generators/win32/winmakefile.h @@ -64,6 +64,9 @@ protected: void processRcFileVar(); static QString cQuoted(const QString &str); virtual QString getManifestFileForRcFile() const; + +public: + ProKey fullTargetVariable() const override; }; QT_END_NAMESPACE diff --git a/tests/auto/tools/qmake/testdata/conflicting_targets/conflicting_targets.pro b/tests/auto/tools/qmake/testdata/conflicting_targets/conflicting_targets.pro new file mode 100644 index 0000000000..c3e8034e35 --- /dev/null +++ b/tests/auto/tools/qmake/testdata/conflicting_targets/conflicting_targets.pro @@ -0,0 +1,5 @@ +TEMPLATE = app +CONFIG += debug_and_release +TARGET = bah +DESTDIR = shu +SOURCES += main.cpp diff --git a/tests/auto/tools/qmake/testdata/conflicting_targets/main.cpp b/tests/auto/tools/qmake/testdata/conflicting_targets/main.cpp new file mode 100644 index 0000000000..39de28135a --- /dev/null +++ b/tests/auto/tools/qmake/testdata/conflicting_targets/main.cpp @@ -0,0 +1,4 @@ +int main(int, char **) +{ + return 0; +} diff --git a/tests/auto/tools/qmake/tst_qmake.cpp b/tests/auto/tools/qmake/tst_qmake.cpp index 1df31904d6..cda4c500e1 100644 --- a/tests/auto/tools/qmake/tst_qmake.cpp +++ b/tests/auto/tools/qmake/tst_qmake.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -82,6 +83,7 @@ private slots: void project(); void proFileCache(); void resources(); + void conflictingTargets(); private: TestCompiler test_compiler; @@ -621,5 +623,18 @@ void tst_qmake::resources() QVERIFY(test_compiler.make(workDir)); } +void tst_qmake::conflictingTargets() +{ + QString workDir = base_path + "/testdata/conflicting_targets"; + QVERIFY(test_compiler.qmake(workDir, "conflicting_targets")); + const QRegularExpression rex("Targets of builds '([^']+)' and '([^']+)' conflict"); + auto match = rex.match(test_compiler.commandOutput()); + QVERIFY(match.hasMatch()); + QStringList builds = { match.captured(1), match.captured(2) }; + std::sort(builds.begin(), builds.end()); + const QStringList expectedBuilds{"Debug", "Release"}; + QCOMPARE(builds, expectedBuilds); +} + QTEST_MAIN(tst_qmake) #include "tst_qmake.moc" -- cgit v1.2.3