diff options
-rw-r--r-- | qmake/library/ioutils.cpp | 23 | ||||
-rw-r--r-- | qmake/library/qmakebuiltins.cpp | 13 | ||||
-rw-r--r-- | qmake/library/qmakeglobals.cpp | 15 | ||||
-rw-r--r-- | tests/auto/tools/qmakelib/evaltest.cpp | 46 | ||||
-rw-r--r-- | tests/auto/tools/qmakelib/tst_qmakelib.cpp | 97 | ||||
-rw-r--r-- | tests/auto/tools/qmakelib/tst_qmakelib.h | 5 |
6 files changed, 157 insertions, 42 deletions
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)) diff --git a/tests/auto/tools/qmakelib/evaltest.cpp b/tests/auto/tools/qmakelib/evaltest.cpp index 03fd4753fd..cf69cc4026 100644 --- a/tests/auto/tools/qmakelib/evaltest.cpp +++ b/tests/auto/tools/qmakelib/evaltest.cpp @@ -34,6 +34,12 @@ #include <qmakeglobals.h> #include <qmakeevaluator.h> +#ifdef Q_OS_WIN +# define EVAL_DRIVE "R:" +#else +# define EVAL_DRIVE +#endif + void tst_qmakelib::addAssignments() { QTest::newRow("assignment") @@ -1599,20 +1605,28 @@ void tst_qmakelib::addReplaceFunctions(const QString &qindir) << true; QTest::newRow("$$absolute_path(): file & path") - << "VAR = $$absolute_path(dir/file.ext, /root/sub)" - << "VAR = /root/sub/dir/file.ext" + << "VAR = $$absolute_path(dir/file.ext, " EVAL_DRIVE "/root/sub)" + << "VAR = " EVAL_DRIVE "/root/sub/dir/file.ext" << "" << true; +#ifdef Q_OS_WIN + QTest::newRow("$$absolute_path(): driveless file & absolute path") + << "VAR = $$absolute_path(/root/sub/dir/file.ext, " EVAL_DRIVE "/other)" + << "VAR = " EVAL_DRIVE "/root/sub/dir/file.ext" + << "" + << true; +#endif + QTest::newRow("$$absolute_path(): absolute file & path") - << "VAR = $$absolute_path(/root/sub/dir/file.ext, /other)" - << "VAR = /root/sub/dir/file.ext" + << "VAR = $$absolute_path(" EVAL_DRIVE "/root/sub/dir/file.ext, " EVAL_DRIVE "/other)" + << "VAR = " EVAL_DRIVE "/root/sub/dir/file.ext" << "" << true; QTest::newRow("$$absolute_path(): empty file & path") - << "VAR = $$absolute_path('', /root/sub)" - << "VAR = /root/sub" + << "VAR = $$absolute_path('', " EVAL_DRIVE "/root/sub)" + << "VAR = " EVAL_DRIVE "/root/sub" << "" << true; @@ -1634,14 +1648,22 @@ void tst_qmakelib::addReplaceFunctions(const QString &qindir) << "" << true; +#ifdef Q_OS_WIN + QTest::newRow("$$relative_path(): driveless file & absolute path") + << "VAR = $$relative_path(/root/sub/dir/file.ext, " EVAL_DRIVE "/root/sub)" + << "VAR = dir/file.ext" + << "" + << true; +#endif + QTest::newRow("$$relative_path(): absolute file & path") - << "VAR = $$relative_path(/root/sub/dir/file.ext, /root/sub)" + << "VAR = $$relative_path(" EVAL_DRIVE "/root/sub/dir/file.ext, " EVAL_DRIVE "/root/sub)" << "VAR = dir/file.ext" << "" << true; QTest::newRow("$$relative_path(): empty file & path") - << "VAR = $$relative_path('', /root/sub)" + << "VAR = $$relative_path('', " EVAL_DRIVE "/root/sub)" << "VAR = ." << "" << true; @@ -2555,20 +2577,20 @@ void tst_qmakelib::addTestFunctions(const QString &qindir) << true; QTest::newRow("touch(): missing target") - << "touch(/does/not/exist, files/other.txt): OK = 1" + << "touch(" EVAL_DRIVE "/does/not/exist, files/other.txt): OK = 1" << "OK = UNDEF" #ifdef Q_OS_WIN - << "##:1: Cannot open /does/not/exist: The system cannot find the path specified." + << "##:1: Cannot open " EVAL_DRIVE "/does/not/exist: The system cannot find the path specified." #else << "##:1: Cannot touch /does/not/exist: No such file or directory." #endif << true; QTest::newRow("touch(): missing reference") - << "touch(" + wpath + ", /does/not/exist): OK = 1" + << "touch(" + wpath + ", " EVAL_DRIVE "/does/not/exist): OK = 1" << "OK = UNDEF" #ifdef Q_OS_WIN - << "##:1: Cannot open reference file /does/not/exist: The system cannot find the path specified." + << "##:1: Cannot open reference file " EVAL_DRIVE "/does/not/exist: The system cannot find the path specified." #else << "##:1: Cannot stat() reference file /does/not/exist: No such file or directory." #endif diff --git a/tests/auto/tools/qmakelib/tst_qmakelib.cpp b/tests/auto/tools/qmakelib/tst_qmakelib.cpp index b1250f4f1a..4a4b20fe50 100644 --- a/tests/auto/tools/qmakelib/tst_qmakelib.cpp +++ b/tests/auto/tools/qmakelib/tst_qmakelib.cpp @@ -42,6 +42,7 @@ void tst_qmakelib::initTestCase() #endif m_prop.insert(ProKey("P1"), ProString("prop val")); m_prop.insert(ProKey("QT_HOST_DATA/get"), ProString(m_indir)); + m_prop.insert(ProKey("QT_HOST_DATA/src"), ProString(m_indir)); QVERIFY(!m_indir.isEmpty()); QVERIFY(QDir(m_outdir).removeRecursively()); @@ -224,21 +225,99 @@ void tst_qmakelib::pathUtils() QVERIFY(IoUtils::isRelativePath(fn0)); QString fn1 = "/a/unix/file/path"; - QVERIFY(IoUtils::isAbsolutePath(fn1)); QCOMPARE(IoUtils::pathName(fn1).toString(), QStringLiteral("/a/unix/file/")); QCOMPARE(IoUtils::fileName(fn1).toString(), QStringLiteral("path")); +} -#ifdef Q_OS_WIN - QString fn0a = "c:file/path"; - QVERIFY(IoUtils::isRelativePath(fn0a)); +void tst_qmakelib::ioUtilRelativity_data() +{ + QTest::addColumn<QString>("path"); + QTest::addColumn<bool>("relative"); - QString fn1a = "c:\\file\\path"; - QVERIFY(IoUtils::isAbsolutePath(fn1a)); + static const struct { + const char *name; + const char *path; + bool relative; + } rows[] = { + { "resource", ":/resource", +#ifdef QMAKE_BUILTIN_PRFS + false +#else + true #endif + }, +#ifdef Q_OS_WIN // all the complications: + // (except UNC: unsupported) + { "drive-abs", "c:/path/to/file", false }, + { "drive-abs-bs", "c:\\path\\to\\file", false }, + { "drive-path", "c:path/to/file.txt", true }, + { "drive-path-bs", "c:path\\to\\file.txt", true }, + { "rooted", "/Users/qt/bin/true", true }, + { "rooted-bs", "\\Users\\qt\\bin\\true", true }, + { "drive-rel", "c:file.txt", true }, + { "subdir-bs", "path\\to\\file", true }, +#else + { "rooted", "/usr/bin/false", false }, +#endif // Q_OS_WIN + { "subdir", "path/to/file", true }, + { "simple", "file.name", true }, + { "empty", "", true } + }; + + for (unsigned int i = sizeof(rows) / sizeof(rows[0]); i-- > 0; ) + QTest::newRow(rows[i].name) << QString::fromLatin1(rows[i].path) + << rows[i].relative; +} + +void tst_qmakelib::ioUtilRelativity() +{ + QFETCH(QString, path); + QFETCH(bool, relative); + + QCOMPARE(IoUtils::isRelativePath(path), relative); +} + +void tst_qmakelib::ioUtilResolve_data() +{ + QTest::addColumn<QString>("base"); + QTest::addColumn<QString>("path"); + QTest::addColumn<QString>("expect"); + + static const struct { + const char *name; + const char *base; + const char *path; + const char *expect; + } data[] = { +#ifdef Q_OS_WIN // all the complications: + { "drive-drive", "a:/ms/dir", "z:/root/file", "z:/root/file" }, + { "drive-drive-bs", "a:\\ms\\dir", "z:\\root\\file", "z:/root/file" }, + { "drive-root", "a:/ms/dir", "/root/file", "a:/root/file" }, + { "drive-root-bs", "a:\\ms\\dir", "\\root\\file", "a:/root/file" }, + { "drive-sub", "a:/ms/dir", "sub/file", "a:/ms/dir/sub/file" }, + { "drive-sub-bs", "a:\\ms\\dir", "sub\\file", "a:/ms/dir/sub/file" }, + { "drive-rel", "a:/ms/dir", "file.txt", "a:/ms/dir/file.txt" }, + { "drive-rel-bs", "a:\\ms\\dir", "file.txt", "a:/ms/dir/file.txt" }, +#else + { "abs-abs", "/a/unix/dir", "/root/file", "/root/file" }, + { "abs-sub", "/a/unix/dir", "sub/file", "/a/unix/dir/sub/file" }, + { "abs-rel", "/a/unix/dir", "file.txt", "/a/unix/dir/file.txt" }, +#endif // Q_OS_WIN + }; + + for (unsigned i = sizeof(data) / sizeof(data[0]); i-- > 0; ) + QTest::newRow(data[i].name) << QString::fromLatin1(data[i].base) + << QString::fromLatin1(data[i].path) + << QString::fromLatin1(data[i].expect); +} + +void tst_qmakelib::ioUtilResolve() +{ + QFETCH(QString, base); + QFETCH(QString, path); + QFETCH(QString, expect); - QString fnbase = "/another/dir"; - QCOMPARE(IoUtils::resolvePath(fnbase, fn0), QStringLiteral("/another/dir/file/path")); - QCOMPARE(IoUtils::resolvePath(fnbase, fn1), QStringLiteral("/a/unix/file/path")); + QCOMPARE(IoUtils::resolvePath(base, path), expect); } void QMakeTestHandler::print(const QString &fileName, int lineNo, int type, const QString &msg) diff --git a/tests/auto/tools/qmakelib/tst_qmakelib.h b/tests/auto/tools/qmakelib/tst_qmakelib.h index e75dedb7ec..acfeb43ecd 100644 --- a/tests/auto/tools/qmakelib/tst_qmakelib.h +++ b/tests/auto/tools/qmakelib/tst_qmakelib.h @@ -48,7 +48,12 @@ private slots: void quoteArgUnix(); void quoteArgWin_data(); void quoteArgWin(); + void pathUtils(); + void ioUtilRelativity_data(); + void ioUtilRelativity(); + void ioUtilResolve_data(); + void ioUtilResolve(); void proString(); void proStringList(); |