From e86f3c018833141776db2d15772ba53995656eac Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Fri, 28 Jul 2017 13:25:27 +0200 Subject: qmake: require a drive in a DOS path for it to be absolute For Q_OS_WIN, a path is only truly absolute if it includes a drive letter; merely starting with a slash is not enough. (We can't support UNC paths, so don't even try: qmake runs various commands in the source directory using CMD.exe, which doesn't support UNC as PWD.) This requires, when resolving a path relative to a root, transcribing the root's drive to such not-quite-absolute paths. Changed QMakeGlobals, $$absolute_path() and $$relative_path() to now use IoUtils::resolvePath() rather than delegating to QDir's absolute path method, since that doesn't correctly recognize the need for a drive letter (and qmake did run into problems with some paths, from splitPathList and a failing test, as a result). Moved existing ioUtils tests for handling of relative / absolute paths out into separate functions and expanded significantly. Fixed some existing tests to use an absolute path where one is needed; added two tests involving driveless (but rooted) paths; and fixed the test init to set a value for QT_HOST_DATA/src property (the lack of which lead to an assertion failure with this fix). Task-number: QTBUG-50839 Change-Id: I2bfc13c1bfbe1ae09997274622ea55cb3de31b43 Reviewed-by: Oswald Buddenhagen --- qmake/library/ioutils.cpp | 23 +++++++++++++++-------- qmake/library/qmakebuiltins.cpp | 13 +++++++------ qmake/library/qmakeglobals.cpp | 15 ++++++++------- 3 files changed, 30 insertions(+), 21 deletions(-) (limited to 'qmake') diff --git a/qmake/library/ioutils.cpp b/qmake/library/ioutils.cpp index 684bcb9a37..afd41912fe 100644 --- a/qmake/library/ioutils.cpp +++ b/qmake/library/ioutils.cpp @@ -66,21 +66,22 @@ IoUtils::FileType IoUtils::fileType(const QString &fileName) bool IoUtils::isRelativePath(const QString &path) { - if (path.startsWith(QLatin1Char('/'))) - return false; #ifdef QMAKE_BUILTIN_PRFS if (path.startsWith(QLatin1String(":/"))) return false; #endif #ifdef Q_OS_WIN - if (path.startsWith(QLatin1Char('\\'))) - return false; - // Unlike QFileInfo, this won't accept a relative path with a drive letter. - // Such paths result in a royal mess anyway ... + // Unlike QFileInfo, this considers only paths with both a drive prefix and + // a subsequent (back-)slash absolute: if (path.length() >= 3 && path.at(1) == QLatin1Char(':') && path.at(0).isLetter() - && (path.at(2) == QLatin1Char('/') || path.at(2) == QLatin1Char('\\'))) + && (path.at(2) == QLatin1Char('/') || path.at(2) == QLatin1Char('\\'))) { return false; -#endif + } + // (... unless, of course, they're UNC, which qmake fails on anyway) +#else + if (path.startsWith(QLatin1Char('/'))) + return false; +#endif // Q_OS_WIN return true; } @@ -100,6 +101,12 @@ QString IoUtils::resolvePath(const QString &baseDir, const QString &fileName) return QString(); if (isAbsolutePath(fileName)) return QDir::cleanPath(fileName); +#ifdef Q_OS_WIN // Add drive to otherwise-absolute path: + if (fileName.at(0).unicode() == '/' || fileName.at(0).unicode() == '\\') { + Q_ASSERT(isAbsolutePath(baseDir)); + return QDir::cleanPath(baseDir.left(2) + fileName); + } +#endif // Q_OS_WIN return QDir::cleanPath(baseDir + QLatin1Char('/') + fileName); } diff --git a/qmake/library/qmakebuiltins.cpp b/qmake/library/qmakebuiltins.cpp index 1b98cbd909..e4b00a6cb3 100644 --- a/qmake/library/qmakebuiltins.cpp +++ b/qmake/library/qmakebuiltins.cpp @@ -1173,9 +1173,9 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinExpand( if (args.count() > 2) { evalError(fL1S("absolute_path(path[, base]) requires one or two arguments.")); } else { - QString rstr = QDir::cleanPath( - QDir(args.count() > 1 ? args.at(1).toQString(m_tmp2) : currentDirectory()) - .absoluteFilePath(args.at(0).toQString(m_tmp1))); + QString arg = args.at(0).toQString(m_tmp1); + QString baseDir = args.count() > 1 ? args.at(1).toQString(m_tmp2) : currentDirectory(); + QString rstr = arg.isEmpty() ? baseDir : IoUtils::resolvePath(baseDir, arg); ret << (rstr.isSharedWith(m_tmp1) ? args.at(0) : args.count() > 1 && rstr.isSharedWith(m_tmp2) @@ -1187,9 +1187,10 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinExpand( if (args.count() > 2) { evalError(fL1S("relative_path(path[, base]) requires one or two arguments.")); } else { - QDir baseDir(args.count() > 1 ? args.at(1).toQString(m_tmp2) : currentDirectory()); - QString rstr = baseDir.relativeFilePath(baseDir.absoluteFilePath( - args.at(0).toQString(m_tmp1))); + QString arg = args.at(0).toQString(m_tmp1); + QString baseDir = args.count() > 1 ? args.at(1).toQString(m_tmp2) : currentDirectory(); + QString absArg = arg.isEmpty() ? baseDir : IoUtils::resolvePath(baseDir, arg); + QString rstr = QDir(baseDir).relativeFilePath(absArg); ret << (rstr.isSharedWith(m_tmp1) ? args.at(0) : ProString(rstr).setSource(args.at(0))); } break; diff --git a/qmake/library/qmakeglobals.cpp b/qmake/library/qmakeglobals.cpp index b6dc8b20b6..d733d479cf 100644 --- a/qmake/library/qmakeglobals.cpp +++ b/qmake/library/qmakeglobals.cpp @@ -68,6 +68,7 @@ #endif QT_BEGIN_NAMESPACE +using namespace QMakeInternal; // for IoUtils #define fL1S(s) QString::fromLatin1(s) @@ -96,9 +97,9 @@ QString QMakeGlobals::cleanSpec(QMakeCmdLineParserState &state, const QString &s { QString ret = QDir::cleanPath(spec); if (ret.contains(QLatin1Char('/'))) { - QString absRet = QDir(state.pwd).absoluteFilePath(ret); + QString absRet = IoUtils::resolvePath(state.pwd, ret); if (QFile::exists(absRet)) - ret = QDir::cleanPath(absRet); + ret = absRet; } return ret; } @@ -126,10 +127,10 @@ QMakeGlobals::ArgumentReturn QMakeGlobals::addCommandLineArguments( user_template_prefix = arg; break; case ArgCache: - cachefile = args[*pos] = QDir::cleanPath(QDir(state.pwd).absoluteFilePath(arg)); + cachefile = args[*pos] = IoUtils::resolvePath(state.pwd, arg); break; case ArgQtConf: - qtconf = args[*pos] = QDir::cleanPath(QDir(state.pwd).absoluteFilePath(arg)); + qtconf = args[*pos] = IoUtils::resolvePath(state.pwd, arg); break; default: if (arg.startsWith(QLatin1Char('-'))) { @@ -259,11 +260,11 @@ QStringList QMakeGlobals::splitPathList(const QString &val) const { QStringList ret; if (!val.isEmpty()) { - QDir bdir; + QString cwd(QDir::currentPath()); const QStringList vals = val.split(dirlist_sep); ret.reserve(vals.length()); for (const QString &it : vals) - ret << QDir::cleanPath(bdir.absoluteFilePath(it)); + ret << IoUtils::resolvePath(cwd, it); } return ret; } @@ -318,7 +319,7 @@ bool QMakeGlobals::initProperties() return false; data = proc.readAll(); #else - if (FILE *proc = QT_POPEN(QString(QMakeInternal::IoUtils::shellQuote(qmake_abslocation) + if (FILE *proc = QT_POPEN(QString(IoUtils::shellQuote(qmake_abslocation) + QLatin1String(" -query")).toLocal8Bit(), QT_POPEN_READ)) { char buff[1024]; while (!feof(proc)) -- cgit v1.2.3 From 957c1d9abd854a3b5c43ace807ab7cbf89c91491 Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Fri, 28 Jul 2017 13:25:41 +0200 Subject: Use a proper test for absolute path for qmake's location QFileInfo.isRelative() deems any path starting with a slash to be absolute; on MS-Win, such paths need a drive specifier (unless they're UNC), so use IoUtils's more robust test for absolute paths. Change-Id: I7d0872a87833cbf1cc1a6ef107941adc4c529624 Reviewed-by: Oswald Buddenhagen --- qmake/option.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'qmake') diff --git a/qmake/option.cpp b/qmake/option.cpp index 4da2a1ae2c..8e457a2626 100644 --- a/qmake/option.cpp +++ b/qmake/option.cpp @@ -28,6 +28,7 @@ #include "option.h" #include "cachekeys.h" +#include #include #include #include @@ -38,6 +39,8 @@ QT_BEGIN_NAMESPACE +using namespace QMakeInternal; + EvalHandler Option::evalHandler; QMakeGlobals *Option::globals; ProFileCache *Option::proFileCache; @@ -325,7 +328,7 @@ Option::init(int argc, char **argv) #endif if(Option::qmake_mode == Option::QMAKE_GENERATE_NOTHING) Option::qmake_mode = default_mode(argv0); - if(!argv0.isEmpty() && !QFileInfo(argv0).isRelative()) { + if (!argv0.isEmpty() && IoUtils::isAbsolutePath(argv0)) { globals->qmake_abslocation = argv0; } else if (argv0.contains(QLatin1Char('/')) #ifdef Q_OS_WIN -- cgit v1.2.3 From aaacae8fe7bb1ca4983cf95fcb8d38320bb21450 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Tue, 23 Jan 2018 09:36:45 +0100 Subject: Document what the QT qmake variable does in more detail Make it clearer what the variable actually does by mentioning that it makes its headers available for inclusion and causes it to be linked to the binary. Change-Id: I72821d4bceea7a92e91175ba6c5acc4c3377d7b7 Reviewed-by: Oswald Buddenhagen --- qmake/doc/src/qmake-manual.qdoc | 3 +++ 1 file changed, 3 insertions(+) (limited to 'qmake') diff --git a/qmake/doc/src/qmake-manual.qdoc b/qmake/doc/src/qmake-manual.qdoc index 9db8a9af48..75a93fd996 100644 --- a/qmake/doc/src/qmake-manual.qdoc +++ b/qmake/doc/src/qmake-manual.qdoc @@ -2279,6 +2279,9 @@ Specifies the \l{All Modules}{Qt modules} that are used by your project. For the value to add for each module, see the module documentation. + At the C++ implementation level, using a Qt module makes its headers + available for inclusion and causes it to be linked to the binary. + By default, \c QT contains \c core and \c gui, ensuring that standard GUI applications can be built without further configuration. -- cgit v1.2.3