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 <kai.koehne@qt.io>
This commit is contained in:
Joerg Bornemann 2019-07-31 13:53:24 +02:00
parent 38cfd3a8cb
commit e75aed1a96
8 changed files with 81 additions and 0 deletions

View File

@ -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

View File

@ -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)

View File

@ -33,6 +33,10 @@
#include "project.h"
#include "cachekeys.h"
#include <algorithm>
#include <iterator>
#include <utility>
#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<Build *, ProString>;
QVector<TargetInfo> 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:

View File

@ -815,4 +815,9 @@ QString Win32MakefileGenerator::getManifestFileForRcFile() const
return QString();
}
ProKey Win32MakefileGenerator::fullTargetVariable() const
{
return "DEST_TARGET";
}
QT_END_NAMESPACE

View File

@ -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

View File

@ -0,0 +1,5 @@
TEMPLATE = app
CONFIG += debug_and_release
TARGET = bah
DESTDIR = shu
SOURCES += main.cpp

View File

@ -0,0 +1,4 @@
int main(int, char **)
{
return 0;
}

View File

@ -33,6 +33,7 @@
#include <QDir>
#include <QDirIterator>
#include <QObject>
#include <QRegularExpression>
#include <QStandardPaths>
#include <QTemporaryDir>
@ -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"